package com.haixiaoke.saas.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson2.JSONObject;
import com.aliyun.oss.model.OSSObject;
import com.haixiaoke.saas.apartment.domain.*;
import com.haixiaoke.saas.apartment.service.ICalendarPriceService;
import com.haixiaoke.saas.apartment.service.IHousingAllocationService;
import com.haixiaoke.saas.apartment.service.IHousingPriceService;
import com.haixiaoke.saas.apartment.service.IUnsubscribeRuleService;
import com.haixiaoke.saas.common.config.WeChatConfig;
import com.haixiaoke.saas.common.constant.*;
import com.haixiaoke.saas.common.core.domain.AjaxResult;
import com.haixiaoke.saas.common.core.redis.RedisCache;
import com.haixiaoke.saas.common.enums.HouseInspectionEnum;
import com.haixiaoke.saas.common.enums.HouseSweepEnum;
import com.haixiaoke.saas.common.enums.OrderStateEnum;
import com.haixiaoke.saas.common.enums.OrderTabEnum;
import com.haixiaoke.saas.common.exception.ServiceException;
import com.haixiaoke.saas.common.oss.OssService;
import com.haixiaoke.saas.common.utils.DateUtils;
import com.haixiaoke.saas.common.utils.GsonUtil;
import com.haixiaoke.saas.common.weChat.domain.ParseParam;
import com.haixiaoke.saas.common.weChat.domain.RefundOrder;
import com.haixiaoke.saas.common.weChat.domain.RefundParam;
import com.haixiaoke.saas.common.weChat.domain.RefundReqInfo;
import com.haixiaoke.saas.common.weChat.service.WeChatService;
import com.haixiaoke.saas.contract.domain.LesseeContract;
import com.haixiaoke.saas.contract.service.ILesseeContractService;
import com.haixiaoke.saas.department.domain.WechatAccount;
import com.haixiaoke.saas.department.service.IWechatAccountService;
import com.haixiaoke.saas.house.domain.House;
import com.haixiaoke.saas.house.domain.HouseInspection;
import com.haixiaoke.saas.house.domain.HouseSweep;
import com.haixiaoke.saas.house.service.IHouseInspectionService;
import com.haixiaoke.saas.house.service.IHouseService;
import com.haixiaoke.saas.house.service.IHouseSweepService;
import com.haixiaoke.saas.houseMember.domain.HouseMember;
import com.haixiaoke.saas.houseMember.service.IHouseMemberService;
import com.haixiaoke.saas.lock.domain.HouseLock;
import com.haixiaoke.saas.lock.domain.LockFace;
import com.haixiaoke.saas.lock.service.IHouseLockService;
import com.haixiaoke.saas.lock.service.ILockFaceService;
import com.haixiaoke.saas.lock.service.LockDevicesService;
import com.haixiaoke.saas.order.domain.*;
import com.haixiaoke.saas.order.mapper.OrderMapper;
import com.haixiaoke.saas.order.service.*;
import com.haixiaoke.saas.order.state.server.IOrderStateServerRole;
import com.haixiaoke.saas.order.state.server.OrderStateServerRole;
import com.haixiaoke.saas.setSwitch.domain.SetSwitch;
import com.haixiaoke.saas.setSwitch.service.ISetSwitchService;
import com.haixiaoke.saas.system.domain.LoginUser;
import com.haixiaoke.saas.system.framework.security.util.SecurityUtils;
import com.haixiaoke.saas.system.service.ISysDictDataService;
import com.haixiaoke.saas.user.domain.CheckInPerson;
import com.haixiaoke.saas.user.domain.UserConsumer;
import com.haixiaoke.saas.user.service.ICheckInPersonService;
import com.haixiaoke.saas.user.service.IUserConsumerService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.*;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.haixiaoke.saas.system.framework.security.util.SecurityUtils.getLoginUser;


/**
 * 订单Service业务层处理
 *
 * @author qixi
 * @date 2024-03-04
 */
@Slf4j
@Service
public class OrderServiceImpl implements IOrderService {
    @Autowired
    private OrderMapper orderMapper;

    @Autowired
    private IHouseService houseService;

    @Autowired
    private IHouseMemberService houseMemberService;

    @Autowired
    private ISetSwitchService setSwitchService;

    @Autowired
    private IOrderAuditRecordService orderAuditRecordService;

    @Autowired
    private IOrderLesseeService orderLesseeService;
    @Autowired
    private IHousingAllocationService housingAllocationService;
    @Autowired
    private ICalendarPriceService calendarPriceService;
    @Autowired
    private IUnsubscribeRuleService unsubscribeRuleService;
    @Autowired
    private IHousingPriceService housingPriceService;
    @Autowired
    private IOrderChargeItemService orderChargeItemService;
    @Autowired
    private IOrderHousingExpensesService orderHousingExpensesService;
    @Autowired
    private IOrderSnapshootService orderSnapshootService;
    @Autowired
    private ICheckInPersonService checkInPersonService;
    @Autowired
    private ISysDictDataService sysDictDataService;
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private IOrderRefundDetailsService orderRefundDetailsService;
    @Autowired
    private IOrderRefundItemService orderRefundItemService;
    @Autowired
    private IWechatPayRecordService wechatPayRecordService;
    @Autowired
    private IOrderStateRecordService orderStateRecordService;
    @Autowired
    private ICheckOutOrderService checkOutOrderService;
    @Autowired
    private IOrderHouseInspectionService orderHouseInspectionService;
    @Autowired
    private WeChatConfig weChatConfig;
    @Autowired
    private IWechatAccountService wechatAccountService;
    @Autowired
    private OssService ossService;
    @Autowired
    private WeChatService weChatService;
    @Autowired
    private ICheckOutSubOrderService checkOutSubOrderService;
    @Autowired
    private IHouseSweepService houseSweepService;
    @Autowired
    private IHouseInspectionService houseInspectionService;
    @Autowired
    private ILesseeContractService lesseeContractService;
    @Autowired
    private IHouseLockService houseLockService;
    @Autowired
    private ILockFaceService lockFaceService;
    @Autowired
    private LockDevicesService lockDevicesService;
    @Autowired
    private IUserConsumerService userConsumerService;


    /**
     * 查询订单
     *
     * @param orderId 订单主键
     * @return 订单
     */
    @Override
    public Order selectOrderByOrderId(String orderId) {
        Order order = orderMapper.selectOrderByOrderId(orderId);
        OrderLessee orderLessee = orderLesseeService.selectOrderLesseeByOrderId(orderId);
        House house = houseService.selectHouseByHouseId(order.getHouseId());
        LesseeContract lesseeContract = lesseeContractService.selectLesseeContractByOrderId(orderId);
        if (ObjectUtil.isNotEmpty(lesseeContract)) {
            order.setContractSignFlag(ContractConstants.HAVE_SIGNED_FLAG);
        } else {
            order.setContractSignFlag(ContractConstants.UN_SIGNED_FLAG);
        }
        order.setLesseeContract(lesseeContract);
        order.setHouse(house);
        order.setOrderLessee(orderLessee);
        return order;
    }

    @Override
    public Order selectOrderById(String orderId) {
        return orderMapper.selectOrderByOrderId(orderId);
    }

    /**
     * 查询订单列表
     *
     * @param order 订单
     * @return 订单
     */
    @Override
    public List<Order> selectOrderList(Order order) {
        List<Order> orders = orderMapper.selectOrderListByOrderLesseeInfo(order);
        for (Order order1 : orders) {
            int memberNumber = houseMemberService.countMemberNumberByOrderId(order1.getOrderId());
            order1.setMemberNumber(memberNumber);
        }
        return orders;
    }

    /**
     * 新增订单
     *
     * @param order 订单
     * @return 结果
     */
    @Override
    public int insertOrder(Order order) {
        order.setCreateTime(DateUtils.getNowDate());
        order.setCreateBy(SecurityUtils.getUsername());
        return orderMapper.insertOrder(order);
    }

    @Override
    public Order insertPreOrder(Order order) {
        buildOrderInfo(order);
        int result = orderMapper.insertOrder(order);
        if (result > 0) {
            return order;
        } else {
            return null;
        }
    }


    private void buildOrderInfo(Order order) {
        String houseId = order.getHouseId();
        House house = houseService.selectHouseById(houseId);
        // String houseJsonStr = JSONUtil.toJsonStr(house);
//        order.setHouseContent(houseJsonStr);
        BeanUtil.copyProperties(house, order);
        String orderId = "O" + System.currentTimeMillis() + RandomUtils.nextInt(10000, 100000);
        order.setOrderId(orderId);

        order.setOrderTab(OrderTabEnum.ORDER_TAB_TO_BE_SIGNED.getValue());
        order.setOrderState(OrderStateEnum.ORDER_STATE_TO_BE_SIGNED.getValue());
        order.setOrderType(Order.ORDER_TYPE_LONG_LEASE);
        order.setTradingMode(OrderConstants.TRADING_MODE_SIGN);
        String estateName = house.getEstateName();
        String buildingName = house.getBuildingName();
        order.setPremisesAddress(estateName + buildingName + "栋" + house.getUnitName() + "单元" + house.getRoomNumber() + "房");
        order.setCreateTime(DateUtils.getNowDate());
        order.setDeptId(getLoginUser().getDeptId());
        order.setCreateBy(getLoginUser().getUsername());
    }

    /**
     * 修改订单
     *
     * @param order 订单
     * @return 结果
     */
    @Override
    public int updateOrder(Order order) {
        order.setUpdateTime(DateUtils.getNowDate());
        // order.setUpdateBy(getLoginUser().getUsername());
        return orderMapper.updateOrder(order);
    }

    /**
     * 修改订单
     *
     * @param order 订单
     * @return 结果
     */
    @Override
    public int updateOrderBySystem(Order order) {
        order.setUpdateTime(DateUtils.getNowDate());
        return orderMapper.updateOrder(order);
    }

    /**
     * 批量删除订单
     *
     * @param orderIds 需要删除的订单主键
     * @return 结果
     */
    @Override
    public int deleteOrderByOrderIds(String[] orderIds) {
        return orderMapper.deleteOrderByOrderIds(orderIds);
    }

    /**
     * 删除订单信息
     *
     * @param orderId 订单主键
     * @return 结果
     */
    @Override
    public int deleteOrderByOrderId(String orderId) {
        return orderMapper.deleteOrderByOrderId(orderId);
    }

    @Override
    public List<Order> selectOrderValidList(Order order) {
        List<Order> orders = orderMapper.selectOrderValidList(order);
        for (Order order1 : orders) {
            int memberNumber = houseMemberService.countMemberNumberByOrderId(order1.getOrderId());
            OrderLessee orderLessee = orderLesseeService.selectOrderLesseeByOrderId(order1.getOrderId());
            if (ObjectUtil.isNotEmpty(orderLessee)) {
                String lesseeType = orderLessee.getLesseeType();
                order1.setLesseeType(lesseeType);
            }

            order1.setMemberNumber(memberNumber);
        }
        return orders;
    }

    @Override
    public List<OrderVO> conditionList(Order order) {
        return orderMapper.conditionList(order);
    }

    @Override
    public List<House> conditionCard(House house) {
        return orderMapper.conditionCard(house);
    }

    @Override
    public int signOrder(LesseeContract lesseeContract) {
        return lesseeContractService.insertLesseeContract(lesseeContract);
    }

    private void dataVerification(Order order) {
        if (order.getDeposit().scale() > 2) {
            throw new ServiceException("押金不能超过两位小数");
        }
        if (OrderStateEnum.RENTAL_MODE_MONTH.getValue().equals(order.getRentalMode())) {
            if (order.getDepositNumber() == null || order.getPayNumber() == null || order.getMonthRent() == null ||
                    order.getDeposit() == null || order.getRentCollectionDate() == null || order.getBillGenerationDate() == null) {
                throw new ServiceException("请输入数据");
            }
            if (order.getMonthRent().scale() > 2) {
                throw new ServiceException("月租金不能超过两位小数");
            }
        } else {
            if (order.getTotalRent() == null) {
                throw new ServiceException("请输入数据");
            }
            if (order.getTotalRent().scale() > 2) {
                throw new ServiceException("总租金不能超过两位小数");
            }
        }
    }

    @Override
    public Boolean checkRepeatOrder(Order order) {
        return orderMapper.checkRepeatOrder(order) > 0;
    }

    @Override
    public void refundRent(Order order) {
        if (order.getRealityCheckOutTime().getTime() < order.getCheckInTime().getTime() || order.getRealityCheckOutTime().getTime() > order.getCheckOutTime().getTime()) {
            throw new ServiceException("退租日期需在租住周期内");
        }

        OrderLessee lessee = orderLesseeService.selectOrderLesseeByOrderId(order.getOrderId());
        order.setOrderLessee(lessee);

        LoginUser loginUser = getLoginUser();
        String tenantId = loginUser.getTenantId();

        SetSwitch setSwitch = setSwitchService.selectSetSwitchByTenantId(tenantId);
        String rentingOutState = setSwitch.getoRentingOutState();
        // 判断是否需要审核 开启审核则提交审核记录
        IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(order);
        if (SetSwitch.AUDITING_STATE_ON.equals(rentingOutState)) {
            orderStateServerRole.refundRentAudit();
        }
        if (SetSwitch.AUDITING_STATE_OFF.equals(rentingOutState)) {
            orderStateServerRole.refundRent();
        }
    }

    @Override
    public void relet(Order order) {

        Order newOrder = order.getOrder();
        if (checkRepeatOrder(newOrder)) {
            throw new ServiceException("房间在入住时间内已出租");
        }

        LoginUser loginUser = getLoginUser();
        String tenantId = loginUser.getTenantId();

        SetSwitch setSwitch = setSwitchService.selectSetSwitchByTenantId(tenantId);
        String continueLeaseState = setSwitch.getoContinueLeaseState();
        // 判断是否需要审核 开启审核则提交审核记录
        IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(order);
        if (SetSwitch.AUDITING_STATE_ON.equals(continueLeaseState)) {
            orderStateServerRole.reletAudit();
        }
        if (SetSwitch.AUDITING_STATE_OFF.equals(continueLeaseState)) {
            orderStateServerRole.relet();
        }
    }

    @Override
    public void exchangeHouse(Order order) {
        Order newOrder = order.getOrder();
        if (checkRepeatOrder(newOrder)) {
            throw new ServiceException("房间在入住时间内已出租");
        }

        if (order.getHouseId().equals(newOrder.getHouseId())) {
            throw new ServiceException("换房不能与原房间一样");
        }

        if (order.getChangeDate().getTime() < order.getCheckInTime().getTime()) {
            throw new ServiceException("换房日期不能在租住周期之前");
        }
        if (order.getChangeDate().getTime() > order.getCheckOutTime().getTime()) {
            throw new ServiceException("换房日期需在租住周期结束之前");
        }

        LoginUser loginUser = getLoginUser();
        String tenantId = loginUser.getTenantId();

        SetSwitch setSwitch = setSwitchService.selectSetSwitchByTenantId(tenantId);
        String exchangeHouseState = setSwitch.getoExchangeHouseState();
        // 判断是否需要审核 开启审核则提交审核记录
        IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(order);
        if (SetSwitch.AUDITING_STATE_ON.equals(exchangeHouseState)) {
            orderStateServerRole.exchangeHouseAudit();
        }
        if (SetSwitch.AUDITING_STATE_OFF.equals(exchangeHouseState)) {
            orderStateServerRole.exchangeHouse();
        }
    }

    @Override
    public void sublease(Order order) {

    /*    Date realityCheckOutTime = order.getRealityCheckOutTime();
        Date checkOutTime = order.getCheckOutTime();
        Date checkInTime = order.getCheckInTime();
        // 判断转租日期是否为租住最后一天
        if (DateUtil.isSameDay(realityCheckOutTime, checkOutTime)) {
            throw new ServiceException("转租日期是租住最后一天，不能转租");
        }

        // 判断转租日期是否先于入住日期
        if (realityCheckOutTime.getTime() < checkInTime.getTime()) {
            throw new ServiceException("转租日期不能先于入住日期");
        }*/

        if (order.getChangeDate().getTime() < order.getCheckInTime().getTime()) {
            throw new ServiceException("转租日期不能在租住周期之前");
        }
        if (order.getChangeDate().getTime() > order.getCheckOutTime().getTime()) {
            throw new ServiceException("转租日期需在租住周期结束之前");
        }

        LoginUser loginUser = getLoginUser();
        String tenantId = loginUser.getTenantId();

        SetSwitch setSwitch = setSwitchService.selectSetSwitchByTenantId(tenantId);
        String subleaseState = setSwitch.getoSubleaseState();
        // 判断是否需要审核 开启审核则提交审核记录
        IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(order);
        if (SetSwitch.AUDITING_STATE_ON.equals(subleaseState)) {
            orderStateServerRole.subleaseAudit();
        }
        if (SetSwitch.AUDITING_STATE_OFF.equals(subleaseState)) {
            orderStateServerRole.sublease();
        }
    }

    /**
     * 订单超时任务
     */
    @Override
    public void orderOvertimeTask() {
        List<Order> orderList = orderMapper.selectOvertimeOrder();
        log.info("订单超时任务开始执行，共{}条订单 id: {}", orderList.size(), orderList.stream().map(Order::getOrderId).collect(Collectors.toList()));
        for (Order order : orderList) {
            IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(order);
            orderStateServerRole.orderOvertime();
        }
    }

    @Override
    public void preOrderSignOvertimeTask() {
        List<Order> orderList = orderMapper.preOrderSignOvertime();
        SetSwitch setSwitch = new SetSwitch();
        List<SetSwitch> setSwitchs = setSwitchService.selectSetSwitchList(setSwitch);
        for (Order order : orderList) {
            String tenantId = order.getTenantId();
            SetSwitch auditing = setSwitchs.stream().filter(body -> body.getTenantId().equals(tenantId)).findAny().get();
            if (SetSwitch.AUDITING_STATE_ON.equals(auditing.getoTimeOutOffState())) {
                IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(order);
                orderStateServerRole.preOrderSignOvertime();
            }
        }


    }

    @Override
    public ConfirmationVO confirmation(String houseId) {
        ConfirmationVO vo = new ConfirmationVO();
        House house = houseService.selectHouseById(houseId);
        HousingAllocation housingAllocation = housingAllocationService.selectHousingAllocationByHouseId(houseId);
        if (ObjectUtil.isEmpty(house) || ObjectUtil.isEmpty(housingAllocation)) {
            throw new ServiceException("数据异常");
        }
        if (HouseConstants.APARTMENT_STATE_DOWN.equals(housingAllocation.getApartmentState())) {
            throw new ServiceException("该房屋已下架");
        }
        List<HousingPrice> housingPriceList = housingPriceService.selectHousingPriceByHouseId(houseId);
        if (CollectionUtil.isEmpty(housingPriceList) || housingPriceList.size() != 7) {
            throw new ServiceException("房屋价格异常");
        }
        UnsubscribeRule unsubscribeRule = unsubscribeRuleService.selectUnsubscribeRuleByUnsubscribeRuleId(housingAllocation.getUnsubscribeRuleId());
        if (ObjectUtil.isEmpty(unsubscribeRule)) {
            throw new ServiceException("房屋数据异常");
        }
        housingAllocation.setTitle(this.packageTitle(house, housingAllocation));
        vo.setHouse(house);
        vo.setHousingAllocation(housingAllocation);
        vo.setHousingPriceList(housingPriceList);
        vo.setUnsubscribeRule(unsubscribeRule);
        return vo;
    }

    public String packageTitle(House house, HousingAllocation allocation) {
        String allocationType = sysDictDataService.selectDictLabel("allocation_type", allocation.getAllocationType());
        String roomType = house.getRoomType();
        return allocationType + house.getHouseArea() + "m²·" + roomType + "室" + allocation.getBedNumber() + "床·" + "可住" + house.getCheckInNumber() + "人";
    }

    @Override
    public ConfirmationVO compute(Date startTime, Date endTime, String orderId, String linkedOrderId, HousingAllocation allocation, List<HousingPrice> housingPriceList, boolean isExpenses, String createBy) {
        ConfirmationVO vo = new ConfirmationVO();
        Date now = DateUtils.getNowDate();
        LocalDate start = startTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();// 起始日期
        LocalDate end = endTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();// 结束日期
        long days = ChronoUnit.DAYS.between(start, end);

        //日历价格，key为星期1~7
        Map<String, HousingPrice> housingPriceMap = housingPriceList.stream().collect(Collectors.toMap(HousingPrice::getWeek, x -> x));

        List<CalendarPrice> calendarPriceList = calendarPriceService.selectCalendarPriceListByTime(allocation.getAllocationId(),
                allocation.getHouseId(), startTime, endTime, false);
        //日历价格，key为时间
        Map<LocalDate, CalendarPrice> calendarPriceMap = calendarPriceList.stream().collect(Collectors.toMap(CalendarPrice::getCalendarTime, x -> x));
        //收费过程
        List<OrderChargeItem> chargeItemList = new ArrayList<>();
        //每日收费详情
        List<OrderHousingExpenses> orderHousingExpensesList = null;
        if (isExpenses) {
            orderHousingExpensesList = new ArrayList<>();
        }
        BigDecimal housePrice = BigDecimal.ZERO;

        while (start.isBefore(end)) {
            BigDecimal sameDayPrice;
            String expensesSource = null;
            if (calendarPriceMap.isEmpty() || ObjectUtil.isEmpty(calendarPriceMap.get(start))) {
                //获取房屋配置的房价
                HousingPrice housingPrice = housingPriceMap.get(String.valueOf(start.getDayOfWeek().getValue()));
                sameDayPrice = housingPrice.getHousePrice();
                if (isExpenses) {
                    expensesSource = OrderConstants.EXPENSES_SOURCE_ALLOCATION;
                }
            } else {
                //获取价格日历里的价格
                CalendarPrice calendarPrice = calendarPriceMap.get(start);
                sameDayPrice = calendarPrice.getCalendarPrice();
                if (isExpenses) {
                    expensesSource = OrderConstants.EXPENSES_SOURCE_CALENDAR;
                }
            }
            //累计相加当天的房费
            housePrice = housePrice.add(sameDayPrice);
            if (isExpenses) {
                OrderHousingExpenses expenses = new OrderHousingExpenses();
                expenses.setOrderId(orderId);
                expenses.setLinkedOrderId(linkedOrderId);
                expenses.setAllocationId(allocation.getAllocationId());
                expenses.setHouseId(allocation.getHouseId());
                expenses.setRentingTime(start);
                expenses.setTenantId(allocation.getTenantId());
                expenses.setRentingExpenses(sameDayPrice);
                expenses.setExpensesSource(expensesSource);
                expenses.setExpensesType(StrUtil.isBlank(linkedOrderId) ?
                        OrderConstants.EXPENSES_TYPE_PLACE_ORDER :
                        OrderConstants.EXPENSES_TYPE_RELET_ORDER);
                expenses.setCreateBy(createBy);
                orderHousingExpensesList.add(expenses);
            }
            //起始时间增加1天
            start = start.plusDays(1);
        }
        //总金额
        BigDecimal totalPrice = housePrice.add(allocation.getCashPledge());

        //订单收费项数据封装
        OrderChargeItem houseCharge = new OrderChargeItem(null, orderId, linkedOrderId, allocation.getAllocationId(), allocation.getHouseId(),
                OrderConstants.CHARGE_TYPE_HOUSE_PRICE, BigDecimal.valueOf(days), housePrice, totalPrice, null);
        if (StrUtil.isBlank(linkedOrderId)) {
            OrderChargeItem pledgeCharge = new OrderChargeItem(null, orderId, linkedOrderId, allocation.getAllocationId(), allocation.getHouseId(),
                    OrderConstants.CHARGE_TYPE_CASH_PLEDGE, BigDecimal.ONE, allocation.getCashPledge(), totalPrice, null);
            chargeItemList.add(pledgeCharge);
        }
        chargeItemList.add(houseCharge);
        //Collections.addAll(chargeItemList, houseCharge, pledgeCharge);
        chargeItemList.forEach(x -> {
            x.setTenantId(allocation.getTenantId());
            x.setCreateTime(now);
            x.setCreateBy(createBy);
        });

        vo.setTotalPrice(totalPrice);
        vo.setOrderChargeItemList(chargeItemList);
        vo.setOrderHousingExpensesList(orderHousingExpensesList);
        vo.setCalendarPriceList(calendarPriceList);
        return vo;
    }

    @Override
    @Transactional
    public Order placeOrder(OrderDTO dto, ConfirmationVO vo) {
        Date nowDate = DateUtils.getNowDate();
        Order order = new Order();
        ConfirmationVO compute = this.compute(dto.getStartTime(), dto.getEndTime(), dto.getOrderId(), null, vo.getHousingAllocation(), vo.getHousingPriceList(), true, dto.getUserConsumer().getUserName());
        BeanUtil.copyProperties(vo.getHouse(), order);
        order.setOrderId(dto.getOrderId());
        order.setOrderTab(OrderTabEnum.ORDER_TAB_TO_BE_SIGNED.getValue());
        order.setOrderState(OrderStateEnum.ORDER_STATE_OBLIGATION.getValue());
        order.setOrderType(Order.ORDER_TYPE_SHORT_LEASE);
        order.setCreateTime(nowDate);
        order.setRentalMode(OrderConstants.RENTAL_MODE_DISPOSABLE);
        order.setOrderSource(OrderConstants.ORDER_SOURCE_ORDER_MANAGEMENT);
        order.setCheckInTime(dto.getStartTime());
        order.setCheckOutTime(dto.getEndTime());
        order.setCreateBy(dto.getUserConsumer().getUserName());
        order.setReserveUser(dto.getUserConsumer().getUserName());
        order.setReserveUserPhone(dto.getUserConsumer().getUserMobile());
        order.setReserveUserId(dto.getUserConsumer().getUserId());
        order.setBeforeHouseId(vo.getHouse().getHouseId());
        List<OrderChargeItem> orderChargeItemList = compute.getOrderChargeItemList();
        if (CollectionUtil.isNotEmpty(orderChargeItemList)) {
            Optional<OrderChargeItem> housePrice = orderChargeItemList.stream().filter(x -> OrderConstants.CHARGE_TYPE_HOUSE_PRICE.equals(x.getChargeType())).findFirst();
            Optional<OrderChargeItem> cashPledge = orderChargeItemList.stream().filter(x -> OrderConstants.CHARGE_TYPE_CASH_PLEDGE.equals(x.getChargeType())).findFirst();
            housePrice.ifPresent(x -> {
                order.setTotalRent(x.getItemSum());
                order.setRentPaidNumber(x.getItemSum());
            });
            cashPledge.ifPresent(x -> {
                order.setDeposit(x.getItemSum());
                order.setDepositPaidNumber(x.getItemSum());
            });
            orderChargeItemService.insertBatchOrderChargeItem(orderChargeItemList);
        }
        if (CollectionUtil.isNotEmpty(compute.getOrderHousingExpensesList())) {
            orderHousingExpensesService.insertBatchOrderHousingExpenses(compute.getOrderHousingExpensesList());
        }
        dto.getMemberIdList().add(dto.getLesseeId());
        List<CheckInPerson> personList = checkInPersonService.selectCheckInPersonByPersonIds(dto.getMemberIdList());
        HousingAllocation allocation = vo.getHousingAllocation();
        List<HouseMember> houseMemberList = new ArrayList<>();
        for (CheckInPerson checkInPerson : personList) {
            UserConsumer userConsumer = userConsumerService.selectUserConsumerByMobile(checkInPerson.getPersonPhone());
            if (ObjectUtil.isEmpty(userConsumer)) {
                userConsumer = new UserConsumer();
                userConsumer.setUserMobile(checkInPerson.getPersonPhone());
                userConsumer.setUserName(checkInPerson.getPersonName());
                userConsumer.setCardNumber(checkInPerson.getIdCard());
                userConsumer.setCreateBy(dto.getUserConsumer().getUserName());
                userConsumerService.insertUserConsumer(userConsumer);
            } else {
                userConsumer.setUserName(checkInPerson.getPersonName());
                userConsumer.setCardNumber(checkInPerson.getIdCard());
                userConsumer.setUpdateTime(nowDate);
                userConsumer.setUpdateBy(dto.getUserConsumer().getUserName());
                userConsumerService.updateUserConsumer(userConsumer);
            }

            HouseMember houseMember = new HouseMember();
            houseMember.setOrderId(dto.getOrderId());
            houseMember.setHouseId(allocation.getHouseId());
            houseMember.setTenantId(allocation.getTenantId());
            houseMember.setMemberName(checkInPerson.getPersonName());
            houseMember.setMemberPhone(checkInPerson.getPersonPhone());
            houseMember.setIdCard(checkInPerson.getIdCard());
            houseMember.setCreateTime(nowDate);
            houseMember.setCreateBy(dto.getUserConsumer().getUserName());
            houseMember.setSex(checkInPerson.getSex());
            houseMember.setUserId(userConsumer.getUserId());
            if (checkInPerson.getPersonId().equals(dto.getLesseeId())) {
                houseMember.setMemberType(HouseMember.MEMBER_TYPE_TENANTRY);
                OrderLessee lessee = new OrderLessee();
                lessee.setHouseId(allocation.getHouseId());
                lessee.setLesseeType(OrderLessee.LESSEE_TYPE_PERSONAL);
                lessee.setLesseeState(OrderLessee.LESSEE_STATE_AFOOT);
                lessee.setOrderId(dto.getOrderId());
                lessee.setLesseeName(checkInPerson.getPersonName());
                lessee.setLesseeSex(checkInPerson.getSex());
                lessee.setCardNumber(checkInPerson.getIdCard());
                lessee.setPhone(checkInPerson.getPersonPhone());
                lessee.setCreateTime(nowDate);
                lessee.setCreateBy(dto.getUserConsumer().getUserName());
                orderLesseeService.insertOrderLessee(lessee);
            } else {
                houseMember.setMemberType(HouseMember.MEMBER_TYPE_TENEMENT);
            }
            houseMemberList.add(houseMember);
        }
        if (!houseMemberList.isEmpty()) {
            houseMemberService.insertBatchHouseMember(houseMemberList);
        }
        OrderSnapshoot snapshoot = new OrderSnapshoot();
        snapshoot.setOrderId(dto.getOrderId());
        snapshoot.setHouseContent(GsonUtil.toJson(vo.getHouse()));
        snapshoot.setAllocationContent(GsonUtil.toJson(vo.getHousingAllocation()));
        snapshoot.setCalendarContent(GsonUtil.toJson(compute.getCalendarPriceList()));
        snapshoot.setUnsubscribeContent(GsonUtil.toJson(vo.getUnsubscribeRule()));
        orderSnapshootService.insertOrderSnapshoot(snapshoot);
        orderMapper.insertOrder(order);
        return order;
    }

    @Override
    public boolean checkRepeatShortOrder(Date startTime, Date endTime, String houseId) {
        return orderMapper.checkRepeatShortOrder(startTime, endTime, houseId) > 0;
    }

    @Override
    public void payCallbackOrder(ParseParam parseParam) {
        //删除redis的key，防止触发缓存过期回调时间
        redisCache.deleteObject(OrderConstants.REDIS_OBLIGATION_ORDER_KEY + parseParam.getOutTradeNo());
        Order order = orderMapper.selectOrderByOrderId(parseParam.getOutTradeNo());
        if (ObjectUtil.isEmpty(order)) {
            log.error("查询不到订单,参数：{}", JSONObject.toJSONString(parseParam));
            return;
        }
        //保存微信支付回到参数
        WechatPayRecord wechatPayRecord = new WechatPayRecord();
        BeanUtil.copyProperties(parseParam, wechatPayRecord);
        wechatPayRecordService.insertWechatPayRecord(wechatPayRecord);
        IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(order);
        orderStateServerRole.orderStayCheckIn(null);
    }

    @Override
    public List<Order> selectOrderByUserId(Order order) {
        List<Order> orderList = orderMapper.selectOrderByUserId(order);
        if (CollectionUtil.isNotEmpty(orderList)) {
            List<String> houseIds = orderList.stream().map(Order::getHouseId).distinct().collect(Collectors.toList());
            List<HousingAllocation> allocationList = housingAllocationService.selectAllocationByHouseIds(houseIds);
            List<House> houseList = houseService.selectHouseByHouseIds(houseIds);
            Map<String, HousingAllocation> allocationMap = allocationList.stream()
                    .collect(Collectors.toMap(HousingAllocation::getHouseId, x -> x));
            Map<String, House> houseMap = houseList.stream().collect(Collectors.toMap(House::getHouseId, x -> x));
            orderList.forEach(x -> {
                List<Order> linkedOrderList = orderMapper.selectOrderByLinkedOrderId(x.getOrderId());
                BigDecimal reletPrice = BigDecimal.ZERO;
                if (CollectionUtil.isNotEmpty(linkedOrderList)) {
                    reletPrice = linkedOrderList.stream().map(Order::getTotalRent).reduce(BigDecimal.ZERO, BigDecimal::add);
                    x.setCheckOutTime(linkedOrderList.get(linkedOrderList.size() - 1).getCheckOutTime());
                }
                x.setTotalRent(x.getTotalRent().add(reletPrice));

                x.setHousingAllocation(allocationMap.get(x.getHouseId()));
                x.setHouse(houseMap.get(x.getHouseId()));
                x.setTotalPrice(x.getDeposit().add(x.getTotalRent()));
                x.getHousingAllocation().setTitle(this.packageTitle(x.getHouse(), x.getHousingAllocation()));
            });
        }
        return orderList;
    }

    @Override
    public List<Order> selectRefundOrderByUserId(Order order) {
        List<Order> orderList = orderMapper.selectRefundOrderByUserId(order);
        if (CollectionUtil.isNotEmpty(orderList)) {
            List<String> orderIds = orderList.stream().map(Order::getOrderId).collect(Collectors.toList());
            List<CheckOutOrder> checkOutOrderList = checkOutOrderService.selectCheckOutOrderByOrderIds(orderIds);
            Map<String, CheckOutOrder> checkOutOrderMap;
            if (CollectionUtil.isNotEmpty(checkOutOrderList)) {
                checkOutOrderMap = checkOutOrderList.stream().collect(Collectors.toMap(CheckOutOrder::getOrderId, x -> x));
            } else {
                checkOutOrderMap = null;
            }
            List<String> houseIds = orderList.stream().map(Order::getHouseId).distinct().collect(Collectors.toList());
            List<House> houseList = houseService.selectHouseByHouseIds(houseIds);
            Map<String, House> houseMap = houseList.stream().collect(Collectors.toMap(House::getHouseId, x -> x));
            List<HousingAllocation> allocationList = housingAllocationService.selectAllocationByHouseIds(houseIds);
            Map<String, HousingAllocation> allocationMap = allocationList.stream()
                    .collect(Collectors.toMap(HousingAllocation::getHouseId, x -> x));
            List<OrderAuditRecord> orderAuditRecordList = orderAuditRecordService.selectOrderAuditRecordByOrderIds(orderIds);

            Map<String, OrderAuditRecord> auditRecordMap;
            if (CollectionUtil.isNotEmpty(orderAuditRecordList)) {
                auditRecordMap = orderAuditRecordList.stream().collect(Collectors.toMap(OrderAuditRecord::getOrderId, x -> x));
            } else {
                auditRecordMap = null;
            }

            orderList.forEach(x -> {
                x.setHouse(houseMap.get(x.getHouseId()));
                x.setHousingAllocation(allocationMap.get(x.getHouseId()));
                x.getHousingAllocation().setTitle(this.packageTitle(x.getHouse(), x.getHousingAllocation()));
                if (checkOutOrderMap != null) {
                    x.setCheckOutOrder(checkOutOrderMap.get(x.getOrderId()));
                }

                if (auditRecordMap != null) {
                    x.setOrderAuditRecord(auditRecordMap.get(x.getOrderId()));
                }
            });
        }
        return orderList;
    }

    @Override
    public Order miniSelectOrderByOrderId(String orderId) {
        Order order = orderMapper.selectOrderByOrderId(orderId);
        if (ObjectUtil.isNotEmpty(order)) {
            if (StrUtil.equals(OrderConstants.SHOW_STATE_NO, order.getShowState())) {
                throw new ServiceException("该订单已经删除");
            }
            if (Order.ORDER_TYPE_LONG_LEASE.equals(order.getOrderType())) {
                throw new ServiceException("订单类型异常");
            }
            if (StrUtil.equals(OrderStateEnum.ORDER_STATE_CHECK_IN.getValue(), order.getOrderState()) ||
                    StrUtil.equals(OrderStateEnum.ORDER_STATE_CHECKING_OUT.getValue(), order.getOrderState()) ||
                    StrUtil.equals(OrderStateEnum.ORDER_STATE_COMPLETED.getValue(), order.getOrderState())) {
                List<Order> orderList = orderMapper.selectOrderByLinkedOrderId(orderId);
                List<Date> payTimeList = new ArrayList<>();
                if (CollectionUtil.isNotEmpty(orderList)) {
                    for (Order reletOrder : orderList) {
                        if (OrderStateEnum.ORDER_STATE_RELET_HAVE_PAID.getValue().equals(reletOrder.getOrderState())) {
                            //统计父订单和续租订单的房费总和
                            order.setTotalRent(order.getTotalRent().add(reletOrder.getTotalRent()));
                            payTimeList.add(reletOrder.getPayTime());
                        }
                    }
                    order.setPayTimeList(payTimeList);
                    order.setReletCheckInTime(orderList.get(0).getCheckInTime());
                    order.setReletCheckOutTime(orderList.get(orderList.size() - 1).getCheckOutTime());
                }
                if (!StrUtil.equals(OrderStateEnum.ORDER_STATE_CHECK_IN.getValue(), order.getOrderState())) {
                    //退房中、已完成订单，查询验房信息及后续补缴后者退款信息
                    CheckOutOrder checkOutOrder = checkOutOrderService.selectCheckOutOrderByOrderId(orderId);
                    order.setCheckOutOrder(checkOutOrder);
                }
            }
            //退订中、退订成功的订单查询订单审核记录、及退订原因
            if (StrUtil.equals(OrderStateEnum.ORDER_STATE_STAY_CHECK_IN.getValue(), order.getOrderState()) ||
                    StrUtil.equals(OrderStateEnum.ORDER_STATE_UNSUBSCRIBING.getValue(), order.getOrderState()) ||
                    StrUtil.equals(OrderStateEnum.ORDER_STATE_UNSUBSCRIBE_SUCCESSFULLY.getValue(), order.getOrderState())) {
                OrderAuditRecord auditRecord = orderAuditRecordService.selectOrderAuditRecordByOrderId(orderId);
                OrderStateRecord stateRecord = orderStateRecordService.selectOrderStateRecordByOrderIdAndState(order.getOrderId(), OrderStateEnum.ORDER_STATE_UNSUBSCRIBING.getValue());
                order.setOrderAuditRecord(auditRecord);
                order.setOrderStateRecord(stateRecord);
            }

            HousingAllocation allocation = housingAllocationService.selectHousingAllocationByHouseId(order.getHouseId());
            House house = houseService.selectHouseById(order.getHouseId());
            OrderLessee lessee = orderLesseeService.selectOrderLesseeByOrderId(orderId);
            String title = packageTitle(house, allocation);
            allocation.setTitle(title);
            order.setHousingAllocation(allocation);
            order.setHouse(house);
            order.setOrderLessee(lessee);
        }
        return order;
    }

    @Override
    public Order miniSelectRefundOrderByOrderId(String orderId) {
        Order order = orderMapper.selectOrderByOrderId(orderId);
        if (ObjectUtil.isNotEmpty(order)) {
            if (StrUtil.equals(OrderConstants.SHOW_STATE_NO, order.getShowState())) {
                throw new ServiceException("该订单已经删除");
            }
            if (Order.ORDER_TYPE_LONG_LEASE.equals(order.getOrderType())) {
                throw new ServiceException("订单类型异常");
            }
            //退房中、已完成订单，查询验房信息及后续补缴后者退款信息
            if (StrUtil.equals(OrderStateEnum.ORDER_STATE_CHECKING_OUT.getValue(), order.getOrderState()) ||
                    StrUtil.equals(OrderStateEnum.ORDER_STATE_COMPLETED.getValue(), order.getOrderState())) {
//                List<Order> orderList = orderMapper.selectOrderByLinkedOrderId(orderId);
                CheckOutOrder checkOutOrder = checkOutOrderService.selectCheckOutOrderByOrderId(orderId);
                order.setCheckOutOrder(checkOutOrder);
            }
            //退订中、退订成功的订单查询订单审核记录、及退订原因
            if (StrUtil.equals(OrderStateEnum.ORDER_STATE_STAY_CHECK_IN.getValue(), order.getOrderState()) ||
                    StrUtil.equals(OrderStateEnum.ORDER_STATE_UNSUBSCRIBING.getValue(), order.getOrderState()) ||
                    StrUtil.equals(OrderStateEnum.ORDER_STATE_UNSUBSCRIBE_SUCCESSFULLY.getValue(), order.getOrderState())) {
                OrderAuditRecord auditRecord = orderAuditRecordService.selectOrderAuditRecordByOrderId(orderId);
                OrderStateRecord stateRecord = orderStateRecordService.selectOrderStateRecordByOrderIdAndState(order.getOrderId(), OrderStateEnum.ORDER_STATE_UNSUBSCRIBING.getValue());
                order.setOrderAuditRecord(auditRecord);
                order.setOrderStateRecord(stateRecord);
            }
            HousingAllocation allocation = housingAllocationService.selectHousingAllocationByHouseId(order.getHouseId());
            House house = houseService.selectHouseById(order.getHouseId());
            OrderLessee lessee = orderLesseeService.selectOrderLesseeByOrderId(orderId);
            String title = packageTitle(house, allocation);
            allocation.setTitle(title);
            order.setHousingAllocation(allocation);
            order.setHouse(house);
            order.setOrderLessee(lessee);
        }
        return order;
    }

    @Override
    public int frontCancelledOrder(String orderId) {
        Order order = orderMapper.selectOrderByOrderId(orderId);
        order.setOperatorId(order.getReserveUserId());
        IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(order);
        return orderStateServerRole.orderCancellation(OrderConstants.RECORD_SOURCE_CONSUMER, null);
    }

    @Override
    public int frontDeletedOrder(String orderId) {
        int result = orderMapper.deleteOrderByOrderId(orderId);
        if (result > 0) {
            orderMapper.deleteOrderByLinkedOrderId(orderId);
        }
        return result;
    }

    @Override
    public OrderRefundVO reservationComputeRefund(String orderId, boolean isRefund) {
        OrderRefundVO vo = new OrderRefundVO();
        Date date = DateUtils.getNowDate();
        Order order = orderMapper.selectOrderByOrderId(orderId);
        if (StrUtil.equals(OrderConstants.SHOW_STATE_NO, order.getShowState())) {
            throw new ServiceException("订单已被删除");
        }
        if (!(OrderStateEnum.ORDER_STATE_STAY_CHECK_IN.getValue().equals(order.getOrderState()) ||
                OrderStateEnum.ORDER_STATE_RELET_HAVE_PAID.getValue().equals(order.getOrderState()))) {
            throw new ServiceException("该订单还未支付，不可退订");
        }
        //退款金额(押金+总租金)
        BigDecimal refundTotal = order.getDeposit().add(order.getTotalRent());
        //订单快照数据
        OrderSnapshoot snapshoot = orderSnapshootService.selectOrderSnapshootByOrderId(orderId);
        HousingAllocation allocation = GsonUtil.toBean(snapshoot.getAllocationContent(), HousingAllocation.class);
        UnsubscribeRule unsubscribeRule = GsonUtil.toBean(snapshoot.getUnsubscribeContent(), UnsubscribeRule.class);
        List<OrderHousingExpenses> housingExpensesList = orderHousingExpensesService.selectHousingExpensesByOrderId(orderId, false);
        List<OrderRefundDetails> refundDetailsList = new ArrayList<>();
        List<OrderRefundItem> orderRefundItemList = new ArrayList<>();
        List<OrderChargeItem> chargeItemList = orderChargeItemService.selectOrderChargeItemByOrderId(orderId);
//        Optional<OrderChargeItem> first = chargeItemList.stream().filter(x -> OrderConstants.CHARGE_TYPE_HOUSE_PRICE.equals(x.getChargeType())).findFirst();
//        OrderChargeItem houseItem = first.orElseGet(() -> orderChargeItemService.selectOrderChargeItemByOrderIdAndChargeType(orderId, OrderConstants.CHARGE_TYPE_HOUSE_PRICE));
        ZonedDateTime zonedDateTime = order.getPayTime().toInstant().atZone(ZoneId.systemDefault());
        //订单预约入住时间
        ZonedDateTime checkInZone = order.getCheckInTime().toInstant().atZone(ZoneId.systemDefault());
        ZonedDateTime checkOutZone = DateUtils.addDays(order.getCheckOutTime(), -1).toInstant().atZone(ZoneId.systemDefault());
        //当前时间的时分秒
        LocalTime nowTime = LocalTime.now();
        //获取当前时间的年月日时分秒
        LocalDateTime nowDateTime = LocalDateTime.now();
        LocalDateTime payDateTime = zonedDateTime.toLocalDateTime();
        //当前时间的年月日
        LocalDate nowDate = LocalDate.now();
        //退房时间年月日
        LocalDate checkOutDate = checkOutZone.toLocalDate();
        if (ChronoUnit.MINUTES.between(payDateTime, nowDateTime) <= 30) {
            this.packageOrderRefundItem(chargeItemList, order, date, orderRefundItemList, BigDecimal.ZERO);
            if (isRefund) {
                for (OrderHousingExpenses expenses : housingExpensesList) {
                    this.packageHousingExpenses(expenses, refundDetailsList, date, OrderConstants.REFUND_STATE_YES, OrderConstants.REFUND_TYPE_UNSUBSCRIBE);
                }
            }
        } else {
            if (HouseConstants.UNSUBSCRIBE_TYPE_STRICT.equals(unsubscribeRule.getUnsubscribeType())) {
                //严格模式
                //获得当前时间前一天的中午12点
                LocalDateTime checkInDateTime = checkInZone.toLocalDateTime();
                LocalDateTime localDateTime = checkInDateTime.withDayOfYear(checkInDateTime.getDayOfYear() - 1).withHour(12).withMinute(0).withSecond(0).withNano(0);
                //比较支付时间是否在入住时间前一天之前,在之前，则全款退,否则只退押金
                LocalDateTime payLocalDateTime = zonedDateTime.toLocalDateTime();
                String refundState;
                if (payLocalDateTime.isBefore(localDateTime)) {
                    refundState = OrderConstants.REFUND_STATE_YES;
                } else {
                    refundState = OrderConstants.REFUND_STATE_NO;
                    //全吃房费
                    refundTotal = order.getDeposit();
                }
                this.packageOrderRefundItem(chargeItemList, order, date, orderRefundItemList, order.getTotalRent());
                for (OrderHousingExpenses expenses : housingExpensesList) {
                    this.packageHousingExpenses(expenses, refundDetailsList, date, refundState, OrderConstants.REFUND_TYPE_UNSUBSCRIBE);
                }
            } else if (HouseConstants.UNSUBSCRIBE_TYPE_HOTEL.equals(unsubscribeRule.getUnsubscribeType())) {
                //酒店模式
                LocalDate checkInDate = checkInZone.toLocalDate();
                LocalTime twelveTime = LocalTime.of(12, 0);//12点
                LocalTime eighteenTime = LocalTime.of(18, 0);//18点
                //折扣的比例
                BigDecimal discount = BigDecimal.ZERO;
                Map<String, Double> unsubscribeContentMap = GsonUtil.toMap(unsubscribeRule.getUnsubscribeContent());
                //当前时间在订单预约入住时间之前，全额退款
                if (nowDate.isBefore(checkInDate)) {
                    this.packageOrderRefundItem(chargeItemList, order, date, orderRefundItemList, BigDecimal.ZERO);
                    for (OrderHousingExpenses expenses : housingExpensesList) {
                        this.packageHousingExpenses(expenses, refundDetailsList, date, OrderConstants.REFUND_STATE_YES, OrderConstants.REFUND_TYPE_UNSUBSCRIBE);
                    }
                } else if (nowDate.equals(checkInDate) && !nowTime.isAfter(eighteenTime)) {
                    //判断当前时间与订单预订入住时间是否为同一天,且时分秒在18点之前或等于，同一天则进入判断
                    boolean flag = false;
                    if (!nowTime.isAfter(twelveTime)) {//现在时间等于或小于12点
                        discount = BigDecimal.valueOf(unsubscribeContentMap.get("1"));
                        flag = true;
                    } else if (!nowTime.isAfter(eighteenTime)) {//现在时间等于或小于18点
                        discount = BigDecimal.valueOf(unsubscribeContentMap.get("2"));
                        flag = true;
                    }
                    //为true则说明时间在0~12~18的范围内
                    if (flag) {
                        //保留四位小数，且四舍五入
                        discount = discount.divide(BigDecimal.valueOf(100)).setScale(4, BigDecimal.ROUND_HALF_UP);
                        //平台吃掉的费用
                        BigDecimal discountPrice = BigDecimal.ZERO;
                        for (OrderHousingExpenses expenses : housingExpensesList) {
                            String refundState = OrderConstants.REFUND_STATE_YES;
                            //替换当天的房费，为折扣后的房费
                            if (nowDate.equals(expenses.getRentingTime())) {
                                //当天要扣掉的房费
                                BigDecimal multiply = expenses.getRentingExpenses().multiply(discount);
                                expenses.setRentingExpenses(multiply);
                                discountPrice = expenses.getRentingExpenses().subtract(multiply);
                                //平台吃掉的费用
                                refundTotal = refundTotal.subtract(discountPrice);
                            }
                            String refundType = packageOrderRefundType(expenses.getRentingTime(), nowDate, refundState);
                            this.packageHousingExpenses(expenses, refundDetailsList, date, refundState, refundType);
                        }
                        for (OrderChargeItem chargeItem : chargeItemList) {
                            OrderRefundItem refundItem = new OrderRefundItem();
                            refundItem.setOrderId(chargeItem.getOrderId());
                            refundItem.setLinkedOrderId(chargeItem.getLinkedOrderId());
                            refundItem.setHouseId(chargeItem.getHouseId());
                            refundItem.setAllocationId(chargeItem.getAllocationId());
                            if (StrUtil.equals(OrderConstants.CHARGE_TYPE_HOUSE_PRICE, chargeItem.getChargeType())) {
                                refundItem.setRefundType(OrderConstants.REFUND_TYPE_HOUSE_PRICE);
                                //判断扣掉的金额和当天的房费是否相等，相等则说明全吃，天数减1
                                /*BigDecimal purchaseQuantity = chargeItem.getPurchaseQuantity();
                                if (housingExpenses.getRentingExpenses().equals(discountPrice)) {
                                    purchaseQuantity = purchaseQuantity.subtract(BigDecimal.ONE);
                                }
                                refundItem.setRefundQuantity(purchaseQuantity);*/
                                refundItem.setItemSum(chargeItem.getItemSum().subtract(discountPrice));
                            } else if (StrUtil.equals(OrderConstants.CHARGE_TYPE_CASH_PLEDGE, chargeItem.getChargeType())) {
                                refundItem.setRefundType(OrderConstants.REFUND_TYPE_CASH_PLEDGE);
                                refundItem.setItemSum(chargeItem.getItemSum());
                            }
                            refundItem.setRefundQuantity(chargeItem.getPurchaseQuantity());
                            refundItem.setTotalPrice(chargeItem.getTotalPrice().subtract(discountPrice));
                            refundItem.setTenantId(order.getTenantId());
                            refundItem.setCreateTime(date);
                            refundItem.setCreateBy(order.getCreateBy());
                            orderRefundItemList.add(refundItem);
                        }
                    }
                } else if ((nowDate.equals(checkInDate) && nowTime.isAfter(eighteenTime)) || (nowDate.isAfter(checkInDate) && !checkOutDate.isAfter(nowDate))) {
                    //入住当天18点后，或者当天时间在入住时间之后且在退房时间之前
                    //获取入住当天18点后的折扣，保留四位小数，且四舍五入
                    discount = BigDecimal.valueOf(unsubscribeContentMap.get("3")).divide(BigDecimal.valueOf(100)).setScale(4, BigDecimal.ROUND_HALF_UP);
                    LocalTime checkOutTime = allocation.getCheckOutTime();
                    //若当前时分秒大于房屋配置里的退房时间，则吃掉当天房费
                    boolean todayFlag = false;
                    if (nowTime.isAfter(checkOutTime)) {
                        todayFlag = true;
                    }
                    //需要吃掉折扣的房费，即不退给用户的房费
                    BigDecimal subtractPrice = BigDecimal.ZERO;

                    for (OrderHousingExpenses expenses : housingExpensesList) {
                        String refundState;
                        //租房时间是否在当前时间之前
                        if (expenses.getRentingTime().isBefore(nowDate)) {
                            refundState = OrderConstants.REFUND_STATE_NO;
                            subtractPrice = subtractPrice.add(expenses.getRentingExpenses());
                        } else {
                            //吃掉之后的折扣，或者吃掉当天的全部或折扣
                            if (todayFlag && nowDate.equals(expenses.getRentingTime())) {
                                //进入判断，说明吃掉当天的房费
                                refundState = OrderConstants.REFUND_STATE_NO;
                                subtractPrice = subtractPrice.add(expenses.getRentingExpenses());
                            } else {
                                refundState = OrderConstants.REFUND_STATE_YES;
                                //统计当前时间之后的被折扣后的房费
                                BigDecimal discountPrice = expenses.getRentingExpenses().multiply(discount);
                                BigDecimal subtract = expenses.getRentingExpenses().subtract(discountPrice);
                                subtractPrice = subtractPrice.add(subtract);
                                //替换当天的房费，为折扣后的房费
                                expenses.setRentingExpenses(discountPrice);
                            }
                        }
                        this.packageHousingExpenses(expenses, refundDetailsList, date, refundState, OrderConstants.REFUND_TYPE_UNSUBSCRIBE);
                    }
                    //退款总金额减去折扣后的房费和订单入住时间到当前时间之前的房费
                    refundTotal = refundTotal.subtract(subtractPrice);

                    //构建退款收费项
                    for (OrderChargeItem chargeItem : chargeItemList) {
                        OrderRefundItem refundItem = new OrderRefundItem();
                        refundItem.setOrderId(chargeItem.getOrderId());
                        refundItem.setLinkedOrderId(chargeItem.getLinkedOrderId());
                        refundItem.setHouseId(chargeItem.getHouseId());
                        refundItem.setAllocationId(chargeItem.getAllocationId());
                        if (StrUtil.equals(OrderConstants.CHARGE_TYPE_HOUSE_PRICE, chargeItem.getChargeType())) {
                            refundItem.setRefundType(OrderConstants.REFUND_TYPE_HOUSE_PRICE);
                            refundItem.setItemSum(chargeItem.getItemSum().subtract(subtractPrice));
                        } else if (StrUtil.equals(OrderConstants.CHARGE_TYPE_CASH_PLEDGE, chargeItem.getChargeType())) {
                            refundItem.setRefundType(OrderConstants.REFUND_TYPE_CASH_PLEDGE);
                            refundItem.setItemSum(chargeItem.getItemSum());
                        }
                        refundItem.setRefundQuantity(chargeItem.getPurchaseQuantity());
                        refundItem.setTotalPrice(chargeItem.getTotalPrice().subtract(subtractPrice));
                        refundItem.setTenantId(order.getTenantId());
                        refundItem.setCreateTime(date);
                        refundItem.setCreateBy(order.getCreateBy());
                        orderRefundItemList.add(refundItem);
                    }
                } else if (nowDate.isAfter(checkOutDate)) {
                    //当前时间在退房时间之后,则房费全吃
                    for (OrderHousingExpenses expenses : housingExpensesList) {
                        String refundState = OrderConstants.REFUND_STATE_NO;
                        //实际退房时间在租房时间之前,则退还房费
                        //全吃房费
                        refundTotal = refundTotal.subtract(expenses.getRentingExpenses());
                        //String refundType = packageOrderRefundType(expenses.getRentingTime(), nowDate, refundState);
                        this.packageHousingExpenses(expenses, refundDetailsList, date, refundState, OrderConstants.REFUND_TYPE_CHECKED_IN);
                    }
                    for (OrderChargeItem chargeItem : chargeItemList) {
                        String refundType = null;
                        OrderRefundItem refundItem = new OrderRefundItem();
                        if (StrUtil.equals(OrderConstants.CHARGE_TYPE_HOUSE_PRICE, chargeItem.getChargeType())) {
                            refundType = OrderConstants.REFUND_TYPE_HOUSE_PRICE;
                            refundItem.setItemSum(BigDecimal.ZERO);
                        } else if (StrUtil.equals(OrderConstants.CHARGE_TYPE_CASH_PLEDGE, chargeItem.getChargeType())) {
                            refundType = OrderConstants.REFUND_TYPE_CASH_PLEDGE;
                            refundItem.setItemSum(chargeItem.getItemSum());
                        }
                        refundItem.setRefundType(refundType);
                        refundItem.setOrderId(chargeItem.getOrderId());
                        refundItem.setLinkedOrderId(chargeItem.getLinkedOrderId());
                        refundItem.setHouseId(chargeItem.getHouseId());
                        refundItem.setAllocationId(chargeItem.getAllocationId());
                        refundItem.setRefundQuantity(chargeItem.getPurchaseQuantity());
                        refundItem.setTenantId(order.getTenantId());
                        refundItem.setCreateTime(date);
                        refundItem.setCreateBy(order.getCreateBy());
                        orderRefundItemList.add(refundItem);
                    }
                    BigDecimal totalPrice = orderRefundItemList.stream().map(OrderRefundItem::getItemSum).reduce(BigDecimal.ZERO, BigDecimal::add);
                    orderRefundItemList.forEach(x -> x.setTotalPrice(totalPrice));
                }
            }
        }
        //封装业务数据
        vo.setRefundTotal(refundTotal);
        vo.setOrderRefundItemList(orderRefundItemList);
        vo.setCheckInTime(order.getCheckInTime());
        vo.setCheckOutTime(order.getCheckOutTime());
        if (isRefund) {
            vo.setOrderRefundDetailsList(refundDetailsList);
        }
        return vo;
    }

    @Override
    public OrderRefundVO refundComputeRefund(String orderId, Date realityCheckOutTime) {
        OrderRefundVO vo = new OrderRefundVO();
        Date date = DateUtils.getNowDate();
        Order orderByOrderId = orderMapper.selectOrderByOrderId(orderId);
        if (StrUtil.equals(OrderConstants.SHOW_STATE_NO, orderByOrderId.getShowState())) {
            throw new ServiceException("订单已被删除");
        }
        if (!OrderStateEnum.ORDER_STATE_CHECK_IN.getValue().equals(orderByOrderId.getOrderState())) {
            throw new ServiceException("订单状态异常，请刷新重来");
        }
        List<Order> orderList = orderMapper.selectOrderByLinkedOrderId(orderId);
        orderList.add(orderByOrderId);
        orderList = orderList.stream()
                .sorted(Comparator.comparing(Order::getCheckInTime))
                .collect(Collectors.toList());
        List<OrderRefundDetails> refundDetailsList = new ArrayList<>();
        List<OrderRefundItem> orderRefundItemList = new ArrayList<>();
        BigDecimal allRefundTotal = BigDecimal.ZERO;
        ZonedDateTime checkOutZonedDateTime = realityCheckOutTime.toInstant().atZone(ZoneId.systemDefault());
        LocalDate realityCheckOutDate = checkOutZonedDateTime.toLocalDate();
        LocalTime realityCheckOutLocalTime = checkOutZonedDateTime.toLocalTime();
        //LocalDateTime realityCheckOutLocalDateTime = checkOutZonedDateTime.toLocalDateTime();
        for (Order order : orderList) {
            //退款金额(押金+总租金)
            BigDecimal refundTotal = order.getDeposit().add(order.getTotalRent());
            //订单快照数据
            OrderSnapshoot snapshoot = orderSnapshootService.selectOrderSnapshootByOrderId(order.getOrderId());
            UnsubscribeRule unsubscribeRule = GsonUtil.toBean(snapshoot.getUnsubscribeContent(), UnsubscribeRule.class);
            //订单每日金额详情
            List<OrderHousingExpenses> housingExpensesList = orderHousingExpensesService.selectHousingExpensesByOrderId(order.getOrderId(), false);
            //订单收费项目
            List<OrderChargeItem> chargeItemList = orderChargeItemService.selectOrderChargeItemByOrderId(order.getOrderId());
            ZonedDateTime checkOutZoned = DateUtils.addDays(order.getCheckOutTime(), -1).toInstant().atZone(ZoneId.systemDefault());
            LocalDate checkOutDate = checkOutZoned.toLocalDate();


            if (HouseConstants.UNSUBSCRIBE_TYPE_STRICT.equals(unsubscribeRule.getUnsubscribeType())) {
                //严格模式
                //this.packageOrderRefundItem(chargeItemList, order, date, orderRefundItemList, true, BigDecimal.ZERO);
                //this.packageOrderRefundItem(houseItem, order, date, orderRefundItemList, order.getTotalRent());

                //用户的退订费
                BigDecimal discountPrice = BigDecimal.ZERO;
                for (OrderHousingExpenses expenses : housingExpensesList) {
                    String refundState;
                    //实际退房时间在租房时间之前,则退还房费
                    if (realityCheckOutDate.isBefore(expenses.getRentingTime())) {
                        refundState = OrderConstants.REFUND_STATE_YES;
                        discountPrice = discountPrice.add(expenses.getRentingExpenses());
                        //全吃房费
                        refundTotal = refundTotal.subtract(expenses.getRentingExpenses());
                    } else {
                        refundState = OrderConstants.REFUND_STATE_NO;
                    }
                    String refundType = packageOrderRefundType(expenses.getRentingTime(), realityCheckOutDate, refundState);
                    this.packageHousingExpenses(expenses, refundDetailsList, date, refundState, refundType);
                }
                for (OrderChargeItem chargeItem : chargeItemList) {
                    String refundType = null;
                    OrderRefundItem refundItem = new OrderRefundItem();
                    if (StrUtil.equals(OrderConstants.CHARGE_TYPE_HOUSE_PRICE, chargeItem.getChargeType())) {
                        refundType = OrderConstants.REFUND_TYPE_HOUSE_PRICE;
                        refundItem.setItemSum(discountPrice);
                    } else if (StrUtil.equals(OrderConstants.CHARGE_TYPE_CASH_PLEDGE, chargeItem.getChargeType())) {
                        refundType = OrderConstants.REFUND_TYPE_CASH_PLEDGE;
                        refundItem.setItemSum(chargeItem.getItemSum());
                    }
                    refundItem.setRefundType(refundType);
                    refundItem.setOrderId(chargeItem.getOrderId());
                    refundItem.setLinkedOrderId(chargeItem.getLinkedOrderId());
                    refundItem.setHouseId(chargeItem.getHouseId());
                    refundItem.setAllocationId(chargeItem.getAllocationId());
                    refundItem.setRefundQuantity(chargeItem.getPurchaseQuantity());

//                    refundItem.setTotalPrice(chargeItem.getTotalPrice().subtract(BigDecimal.ZERO));
                    refundItem.setTenantId(order.getTenantId());
                    refundItem.setCreateTime(date);
                    refundItem.setCreateBy(order.getCreateBy());
                    orderRefundItemList.add(refundItem);
                }
                BigDecimal totalPrice = orderRefundItemList.stream().map(OrderRefundItem::getItemSum).reduce(BigDecimal.ZERO, BigDecimal::add);
                orderRefundItemList.forEach(x -> x.setTotalPrice(totalPrice));
            } else if (HouseConstants.UNSUBSCRIBE_TYPE_HOTEL.equals(unsubscribeRule.getUnsubscribeType())) {
                //酒店模式
                //订单预约入住时间
                LocalTime twelveTime = LocalTime.of(12, 0);//12点
                LocalTime eighteenTime = LocalTime.of(18, 0);//18点
                //折扣的比例
                BigDecimal discount = BigDecimal.ZERO;
                Map<String, Double> unsubscribeContentMap = GsonUtil.toMap(unsubscribeRule.getUnsubscribeContent());
                //实际退房时间在订单预约退房时间之前
                if (realityCheckOutDate.isBefore(checkOutDate)) {
                    if (!realityCheckOutLocalTime.isAfter(twelveTime)) {//现在时间等于或小于12点
                        discount = BigDecimal.valueOf(unsubscribeContentMap.get("1"));
                    } else if (!realityCheckOutLocalTime.isAfter(eighteenTime)) {//现在时间等于或小于18点
                        discount = BigDecimal.valueOf(unsubscribeContentMap.get("2"));
                    } else {
                        discount = BigDecimal.valueOf(unsubscribeContentMap.get("3"));
                    }
                    //保留四位小数，且四舍五入
                    discount = discount.divide(BigDecimal.valueOf(100)).setScale(4, BigDecimal.ROUND_HALF_UP);
                    //用户的退订费
                    BigDecimal discountPrice = BigDecimal.ZERO;
                    for (OrderHousingExpenses expenses : housingExpensesList) {
                        String refundState;
                        //实际退房时间在租房时间之前,则退还房费
                        if (realityCheckOutDate.isBefore(expenses.getRentingTime())) {
                            refundState = OrderConstants.REFUND_STATE_YES;
                            //当天要扣掉的房费
                            BigDecimal multiply = expenses.getRentingExpenses().multiply(discount);
                            discountPrice = discountPrice.add(multiply);
                            //退款金额需扣除折扣后的房费
                            expenses.setRentingExpenses(multiply);
                            BigDecimal subtract = expenses.getRentingExpenses().subtract(multiply);
                            //平台吃掉的费用
                            refundTotal = refundTotal.subtract(subtract);
                        } else {
                            refundState = OrderConstants.REFUND_STATE_NO;
                        }
                        String refundType = packageOrderRefundType(expenses.getRentingTime(), realityCheckOutDate, refundState);
                        this.packageHousingExpenses(expenses, refundDetailsList, date, refundState, refundType);
                    }
                    for (OrderChargeItem chargeItem : chargeItemList) {
                        OrderRefundItem refundItem = new OrderRefundItem();
                        String refundType = null;
                        if (StrUtil.equals(OrderConstants.CHARGE_TYPE_HOUSE_PRICE, chargeItem.getChargeType())) {
                            refundType = OrderConstants.REFUND_TYPE_HOUSE_PRICE;
                            refundItem.setItemSum(discountPrice);
                        } else if (StrUtil.equals(OrderConstants.CHARGE_TYPE_CASH_PLEDGE, chargeItem.getChargeType())) {
                            refundType = OrderConstants.REFUND_TYPE_CASH_PLEDGE;
                            refundItem.setItemSum(chargeItem.getItemSum());
                        }
                        refundItem.setRefundType(refundType);
                        refundItem.setOrderId(chargeItem.getOrderId());
                        refundItem.setLinkedOrderId(chargeItem.getLinkedOrderId());
                        refundItem.setHouseId(chargeItem.getHouseId());
                        refundItem.setAllocationId(chargeItem.getAllocationId());
                        refundItem.setRefundQuantity(chargeItem.getPurchaseQuantity());
//                        refundItem.setTotalPrice(chargeItem.getTotalPrice());
                        refundItem.setTenantId(order.getTenantId());
                        refundItem.setCreateTime(date);
                        refundItem.setCreateBy(order.getCreateBy());
                        orderRefundItemList.add(refundItem);
                    }
                    BigDecimal totalPrice = orderRefundItemList.stream().map(OrderRefundItem::getItemSum).reduce(BigDecimal.ZERO, BigDecimal::add);
                    orderRefundItemList.forEach(x -> x.setTotalPrice(totalPrice));
                } else {
                    //实际退房时间在订单预约退房时间之后,或者为同一天
                    //用户的退订费
                    BigDecimal discountPrice = BigDecimal.ZERO;
                    for (OrderHousingExpenses expenses : housingExpensesList) {
                        String refundState;
                        if (realityCheckOutDate.isBefore(expenses.getRentingTime())) {
                            refundState = OrderConstants.REFUND_STATE_YES;
                            discountPrice = discountPrice.add(expenses.getRentingExpenses());
                        } else {
                            refundState = OrderConstants.REFUND_STATE_NO;
                        }
                        String refundType = packageOrderRefundType(expenses.getRentingTime(), realityCheckOutDate, refundState);
                        this.packageHousingExpenses(expenses, refundDetailsList, date, refundState, refundType);
                    }
                    for (OrderChargeItem chargeItem : chargeItemList) {
                        OrderRefundItem refundItem = new OrderRefundItem();
                        refundItem.setOrderId(chargeItem.getOrderId());
                        refundItem.setLinkedOrderId(chargeItem.getLinkedOrderId());
                        refundItem.setHouseId(chargeItem.getHouseId());
                        refundItem.setAllocationId(chargeItem.getAllocationId());
                        if (StrUtil.equals(OrderConstants.CHARGE_TYPE_HOUSE_PRICE, chargeItem.getChargeType())) {
                            refundItem.setRefundType(OrderConstants.REFUND_TYPE_HOUSE_PRICE);
                            refundItem.setItemSum(discountPrice);
                        } else if (StrUtil.equals(OrderConstants.CHARGE_TYPE_CASH_PLEDGE, chargeItem.getChargeType())) {
                            refundItem.setRefundType(OrderConstants.REFUND_TYPE_CASH_PLEDGE);
                            refundItem.setItemSum(chargeItem.getItemSum());
                        }
                        refundItem.setRefundQuantity(chargeItem.getPurchaseQuantity());
                        refundItem.setTotalPrice(chargeItem.getTotalPrice());
                        refundItem.setTenantId(order.getTenantId());
                        refundItem.setCreateTime(date);
                        refundItem.setCreateBy(order.getCreateBy());
                        orderRefundItemList.add(refundItem);
                    }
                    BigDecimal totalPrice = orderRefundItemList.stream().map(OrderRefundItem::getItemSum).reduce(BigDecimal.ZERO, BigDecimal::add);
                    orderRefundItemList.forEach(x -> x.setTotalPrice(totalPrice));
                }
            }
            allRefundTotal = allRefundTotal.add(refundTotal);
        }

        //封装业务数据
        vo.setRefundTotal(allRefundTotal);
        vo.setOrderRefundItemList(orderRefundItemList);
        vo.setCheckInTime(orderList.get(0).getCheckInTime());
        vo.setCheckOutTime(orderList.get(orderList.size() - 1).getCheckOutTime());
        vo.setOrderRefundDetailsList(refundDetailsList);
        return vo;
    }

    public String packageOrderRefundType(LocalDate rentingTime, LocalDate checkOutDate, String refundState) {
        String refundType = OrderConstants.REFUND_TYPE_CHECKED_IN;
        //租赁时间在退房时间之后的,则是退订费类型
        if (rentingTime.isAfter(checkOutDate)) {
            refundType = OrderConstants.REFUND_TYPE_UNSUBSCRIBE;
        } else if (rentingTime.isEqual(checkOutDate) && OrderConstants.REFUND_STATE_YES.equals(refundState)) {
            refundType = OrderConstants.REFUND_TYPE_UNSUBSCRIBE;
        }
        return refundType;
    }

    @Override
    @Transactional
    public int cancelReservation(OrderStateRecord orderStateRecord, String userName, Long userId, String auditSource) {
        OrderRefundVO vo = this.reservationComputeRefund(orderStateRecord.getOrderId(), true);
        if (CollectionUtil.isEmpty(vo.getOrderRefundItemList())) {
            throw new ServiceException("退费记录异常");
        }
        /*if (CollectionUtil.isEmpty(vo.getOrderRefundDetailsList())) {
            throw new ServiceException("房费详情记录异常");
        }*/

        Order order = orderMapper.selectOrderByOrderId(orderStateRecord.getOrderId());
        OrderLessee lessee = orderLesseeService.selectOrderLesseeByOrderId(order.getOrderId());

        //审核申请数据记录
        OrderAuditRecord auditRecord = new OrderAuditRecord();
        auditRecord.setOrderContent(JSONUtil.toJsonStr(order));
        auditRecord.setOrderId(order.getOrderId());
        auditRecord.setTenantId(order.getTenantId());
        auditRecord.setAuditRecordType(OrderConstants.AUDIT_RECORD_TYPE_CANCEL_RESERVATION);
        auditRecord.setAuditRecordState(OrderConstants.AUDIT_RECORD_STATE_AUDIT);
        auditRecord.setAuditProcess(OrderConstants.AUDIT_PROCESS_PENDING);
        auditRecord.setAuditSource(auditSource);
        auditRecord.setAddress(order.getPremisesAddress());
        auditRecord.setCreateBy(userName);
        auditRecord.setOperatorId(userId);
        auditRecord.setLodgerName(lessee.getLesseeName());
        auditRecord.setLodgerPhone(lessee.getPhone());
        int result = orderAuditRecordService.insertOrderAuditRecord(auditRecord);
        if (result <= 0) {
            throw new ServiceException("审核记录保存失败");
        }
        //插入退费相关信息
        vo.getOrderRefundItemList().forEach(x -> x.setRecordId(auditRecord.getRecordId()));
        orderRefundItemService.insertBatchOrderRefundItem(vo.getOrderRefundItemList());

        vo.getOrderRefundDetailsList().forEach(x -> x.setRecordId(auditRecord.getRecordId()));
        orderRefundDetailsService.insertBatchOrderRefundDetails(vo.getOrderRefundDetailsList());

        //存放缓存,1小时后自动审核通过
        redisCache.setCacheObject(OrderConstants.REDIS_AUDIT_ORDER_KEY + auditRecord.getRecordId(), auditRecord, 1, TimeUnit.HOURS);

        //更改订单状态
        order.setOperatorId(userId);
        order.setRefundAmount(vo.getRefundTotal());
        IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(order);
        return orderStateServerRole.cancelReservation(orderStateRecord.getRecordSource(), orderStateRecord.getRecordReason());
    }

    @Override
    public List<Order> selectApartmentOrderList(Order order) {
        List<Order> orderList = orderMapper.selectApartmentOrderList(order);
        if ("1".equals(order.getSearchValue()) && CollectionUtil.isNotEmpty(orderList)) {
            for (Order orderById : orderList) {
                List<Order> linkedOrderList = orderMapper.selectOrderByLinkedOrderId(orderById.getOrderId());
                if (CollectionUtil.isNotEmpty(linkedOrderList)) {
                    orderById.setCheckOutTime(linkedOrderList.get(linkedOrderList.size() - 1).getCheckOutTime());
                }
            }
        }
        return orderList;
    }

    @Override
    public void cancelReservationCallbackOrder(RefundParam refundParam, RefundReqInfo reqInfo) {
        String outTradeNo = reqInfo.getOutTradeNo();
        Order order = orderMapper.selectOrderByOrderId(outTradeNo);
        OrderAuditRecord auditRecord = orderAuditRecordService.selectOrderAuditRecordByOrderId(outTradeNo);
        if (ObjectUtil.isEmpty(order) || ObjectUtil.isEmpty(auditRecord)) {
            log.info("当前退款回调的单号查询不到订单数据:{},{}", GsonUtil.toJson(refundParam), GsonUtil.toJson(reqInfo));
            return;
        }
        if (!OrderStateEnum.ORDER_STATE_UNSUBSCRIBING.getValue().equals(order.getOrderState()) ||
                !(OrderConstants.AUDIT_PROCESS_REFUND.equals(auditRecord.getAuditProcess()) ||
                        OrderConstants.AUDIT_PROCESS_REFUND_SUCCESSFUL.equals(auditRecord.getAuditProcess()) ||
                        OrderConstants.AUDIT_PROCESS_REFUND_EXCEPTION.equals(auditRecord.getAuditProcess()))) {
            log.info("退订回调状态异常，订单状态:{},审核状态:{}", order.getOrderState(), auditRecord.getAuditProcess());
            return;
        }
        if (StrUtil.isNotBlank(refundParam.getReturnCode()) && StrUtil.equals(refundParam.getReturnCode(), "SUCCESS")) {
            IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(order);
            orderStateServerRole.unsubscribeSuccessfully(OrderConstants.RECORD_SOURCE_ENTERPRISE, null);
            auditRecord.setAuditProcess(OrderConstants.AUDIT_PROCESS_REFUND_SUCCESSFUL);
        } else {
            auditRecord.setAuditProcess(OrderConstants.AUDIT_PROCESS_REFUND_EXCEPTION);
        }
        orderAuditRecordService.updateOrderAuditRecord(auditRecord);

        //更改租客状态
        houseMemberService.deleteHouseMemberByOrderId(order.getOrderId());
        //更改承租人状态
        orderLesseeService.rentingTerminationByOrderId(order.getOrderId());
    }

    @Override
    public Order selectApartmentOrderByOrderId(String orderId) {
        Order order = orderMapper.selectOrderByOrderId(orderId);
        OrderLessee orderLessee = orderLesseeService.selectOrderLesseeByOrderId(orderId);
        order.setOrderLessee(orderLessee);
        if (StrUtil.equals(Order.ORDER_TYPE_SHORT_LEASE, order.getOrderType())) {
            OrderSnapshoot snapshoot = orderSnapshootService.selectOrderUnsubscribeRuleByOrderId(orderId);
            order.setUnsubscribeRule(GsonUtil.toBean(snapshoot.getUnsubscribeContent(), UnsubscribeRule.class));

            List<Order> orderList = orderMapper.selectOrderByLinkedOrderId(orderId);
            BigDecimal reletPrice = BigDecimal.ZERO;
            if (CollectionUtil.isNotEmpty(orderList)) {
                reletPrice = orderList.stream().map(Order::getTotalRent).reduce(BigDecimal.ZERO, BigDecimal::add);
                order.setCheckOutTime(orderList.get(orderList.size() - 1).getCheckOutTime());
            }
            order.setTotalRent(order.getTotalRent().add(reletPrice));
        }
        return order;
    }

    @Override
    public Order selectHouseDynamicOrderByOrderId(String orderId) {
        Order order = orderMapper.selectOrderByOrderId(orderId);
        if (ObjectUtil.isNotEmpty(order)) {
            //承租人信息
            OrderLessee orderLessee = orderLesseeService.selectOrderLesseeByOrderId(orderId);
            order.setOrderLessee(orderLessee);

            if (StrUtil.equals(Order.ORDER_TYPE_LONG_LEASE, order.getOrderType())) {
                //长短租
                House house = houseService.selectHouseByHouseId(order.getHouseId());
                order.setHouse(house);

                //检验租客合同相关标识
                Order selectState = orderMapper.selectLesseeContractStateByOrderId(orderId);
                order.setNewContractFlag(selectState.getNewContractFlag());
                order.setContractSignFlag(selectState.getContractSignFlag());
            } else if (StrUtil.equals(Order.ORDER_TYPE_SHORT_LEASE, order.getOrderType())) {
                //日租
                if (!StrUtil.equals(order.getHouseId(), order.getBeforeHouseId())) {
                    House house = houseService.selectHouseById(order.getHouseId());
                    order.setHouseNew(house);
                }
                order.setCheckLinkedOrder(this.checkLinkedOrder(orderId));
                if (StrUtil.equals(Order.ORDER_TYPE_SHORT_LEASE, order.getOrderType())) {
                    OrderSnapshoot snapshoot = orderSnapshootService.selectOrderSnapshootByOrderId(orderId);
                    order.setUnsubscribeRule(GsonUtil.toBean(snapshoot.getUnsubscribeContent(), UnsubscribeRule.class));
                    order.setHousingAllocation(GsonUtil.toBean(snapshoot.getAllocationContent(), HousingAllocation.class));
                    order.setHouse(GsonUtil.toBean(snapshoot.getHouseContent(), House.class));
                    order.setRentDay((int) DateUtil.betweenDay(order.getCheckInTime(), order.getCheckOutTime(), false));
                    List<Order> orderList = orderMapper.selectOrderByLinkedOrderId(orderId);
                    BigDecimal reletPrice = BigDecimal.ZERO;
                    if (CollectionUtil.isNotEmpty(orderList)) {
                        reletPrice = orderList.stream().map(Order::getTotalRent).reduce(BigDecimal.ZERO, BigDecimal::add);
                        order.setCheckOutTime(orderList.get(orderList.size() - 1).getCheckOutTime());
                    }
                    order.setReletPrice(reletPrice);

                    if (OrderStateEnum.ORDER_STATE_CHECKING_OUT.getValue().equals(order.getOrderState()) ||
                            OrderStateEnum.ORDER_STATE_COMPLETED.getValue().equals(order.getOrderState())) {
                        CheckOutOrder checkOutOrder = checkOutOrderService.selectCheckOutOrderByOrderId(orderId);
                        order.setCheckOutOrder(checkOutOrder);
                        List<OrderRefundItem> orderRefundItems = orderRefundItemService.selectOrderRefundItemByOrderId(orderId);
                        order.setOrderRefundItemList(orderRefundItems);
                        List<OrderRefundDetails> orderRefundDetailsList = orderRefundDetailsService.countRefundPriceByRefundType(orderId);
                        order.setCheckInPrice(BigDecimal.ZERO);
                        order.setUnsubscribePrice(BigDecimal.ZERO);
                        if (CollectionUtil.isNotEmpty(orderRefundDetailsList)) {
                            for (OrderRefundDetails refundDetails : orderRefundDetailsList) {
                                if (OrderConstants.REFUND_TYPE_CHECKED_IN.equals(refundDetails.getRefundType())) {
                                    order.setCheckInPrice(refundDetails.getRefundPrice());
                                } else if (OrderConstants.REFUND_TYPE_UNSUBSCRIBE.equals(refundDetails.getRefundType())) {
                                    order.setUnsubscribePrice(refundDetails.getRefundPrice());
                                }
                            }
                        }
                    }

                    //退订中查询审核信息
                    if (StrUtil.equals(OrderStateEnum.ORDER_STATE_UNSUBSCRIBING.getValue(), order.getOrderState())) {
                        OrderAuditRecord auditRecord = orderAuditRecordService.selectOrderAuditRecordByOrderId(orderId);
                        order.setOrderAuditRecord(auditRecord);
                    }
                }


                HouseSweep houseSweep = houseSweepService.selectHouseSweepByHouseId(order.getHouseId());
                if (ObjectUtil.isNotEmpty(houseSweep)) {
                    order.setSweepState(houseSweep.getSweepState());
                } else {
                    order.setSweepState(HouseSweepEnum.SWEEP_STATE_FULFILL.getValue());
                }

                HouseInspection inspection = new HouseInspection();
                inspection.setOrderId(orderId);
                inspection.setInspectionState(HouseInspectionEnum.INSPECTION_STATE_FULFILL.getValue());
                inspection.setInspectionResult(HouseInspectionEnum.INSPECTION_RESULT_DAMAGE.getValue());
                List<HouseInspection> houseInspectionList = houseInspectionService.selectHouseInspectionByOrderId(inspection);
                if (CollectionUtil.isNotEmpty(houseInspectionList)) {
                    String[] houseInspectionIds = houseInspectionList.stream().map(HouseInspection::getHouseInspectionId).toArray(String[]::new);
                    order.setInspectionResult(houseInspectionList.get(0).getInspectionResult());
                    order.setHouseInspectionIds(houseInspectionIds);
                } else {
                    order.setInspectionResult(HouseInspectionEnum.INSPECTION_RESULT_NORMAL.getValue());
                }
            }
        }
        return order;
    }

    @Override
    public int checkIn(Order order, String recordSource, Long userId) {
        Order byOrderId = orderMapper.selectOrderByOrderId(order.getOrderId());
        byOrderId.setRealityCheckInTime(order.getRealityCheckInTime());

        //变更已入住
        IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(byOrderId);
        return orderStateServerRole.orderCheckIn(recordSource, userId);
    }

    @Override
    public boolean checkLinkedOrderState(String orderId) {
        int result = orderMapper.checkLinkedOrderState(orderId);
        return result > 0;
    }

    @Override
    public int apartmentExchangeHouse(Order order) {
        orderLesseeService.updateOrderLesseeByOrderId(order.getOrderId(), order.getHouseId());
        // 修改订单金额信息
        orderChargeItemService.updateOrderChargeItemByOrderId(order.getOrderId(), order.getHouseId());
        // 修改房屋价格信息
        orderHousingExpensesService.updateExpensesByOrderIdAndLinkedOrderId(order.getOrderId(), order.getHouseId());

        //当前时间
        Date nowDate = DateUtils.getNowDate();

        //换房前的所有状态正常的锁数据
        List<HouseLock> beforeHouseLockList = houseLockService.selectHouseLockByHouseIdAndLockState(order.getBeforeHouseId(),LockConstants.LOCK_STATE_NORMAL);
        if (CollectionUtil.isNotEmpty(beforeHouseLockList)) {
            for (HouseLock lock : beforeHouseLockList) {
                //删除换房前的租客用户人脸信息
                List<LockFace> tenantLockFaces = lockFaceService.selectLockFaceByLockIdAndUserType(lock.getLockId(), LockConstants.USER_TYPE_TENANT);
                if (CollectionUtil.isNotEmpty(tenantLockFaces)) {
                    for (LockFace lockFace : tenantLockFaces) {
                        HouseLock houseLock = new HouseLock();
                        houseLock.setMac(lockFace.getMac());
                        houseLockService.disableLockFaceAndFaceState(houseLock, lockFace);
                    }
                }

                //授权换房前的房管家人脸信息
                List<LockFace> adminLockFaces = lockFaceService.selectLockFaceByLockIdAndUserType(lock.getLockId(), LockConstants.USER_TYPE_MANAGER);
                if (CollectionUtil.isNotEmpty(adminLockFaces)) {
                    for (LockFace lockFace : adminLockFaces) {
                        houseLockService.authorizationLockFace(lock.getMac(), lockFace);
                    }
                }
            }
        }
        //删除冻结锁的业务数据
        houseLockService.removeLockPwdAndLockFace(order.getOrderId());

        //查询所有房屋成员
        List<HouseMember> houseMemberList = houseMemberService.selectHouseMemberListByHouseId(order.getBeforeHouseId());

            // 换房后的所有状态正常的锁数据
            List<HouseLock> houseLockList = houseLockService.selectHouseLockByHouseIdAndLockState(order.getHouseId(),LockConstants.LOCK_STATE_NORMAL);
            if (CollectionUtil.isNotEmpty(houseLockList)) {
                for (HouseLock lock : houseLockList) {
                    // 删除房管家人脸授权信息
                    List<LockFace> adminLockFaceList = lockFaceService.selectLockFaceListAndHouseIdAndUserTypeAndFaceState(order.getHouseId(), LockConstants.USER_TYPE_MANAGER, LockConstants.FACE_STATE_ENABLED);
                    if (CollectionUtil.isNotEmpty(adminLockFaceList)) {
                        for (LockFace lockFace : adminLockFaceList) {
                            HouseLock houseLock = new HouseLock();
                            houseLock.setMac(lock.getMac());
                            houseLockService.disableLockFaceAndFaceState(houseLock, lockFace);
                        }
                    }

                    if (CollectionUtil.isNotEmpty(houseMemberList)) {
                        //授权新房的租客人脸信息
                        List<LockFace> lockFaceList = new ArrayList<>();
                        for (HouseMember houseMember : houseMemberList) {
                            houseMember.setHouseId(order.getHouseId());
                            if (StrUtil.equals(HouseMemberConstants.AUTH_STATE_NO, houseMember.getAuthState()) &&
                                    StrUtil.isNotBlank(houseMember.getFacePhoto())) {
                                LockFace lockFace = lockFaceService.createLockFace(lock, houseMember, nowDate);
                                lockFaceList.add(lockFace);

                            }
                        }
                        //批量插入人脸授权信息
                        lockFaceService.insertBatchLockFace(lockFaceList);
                        // 修改房屋成员所属信息
                        houseMemberService.updateBatchHouseMember(houseMemberList);
                    }
                }
            }

        House house = houseService.selectHouseById(order.getHouseId());
        order.setHouse(house);
        return orderMapper.apartmentExchangeHouse(order);
    }

    @Override
    @Transactional
    public int apartmentRelet(Order order) {
        Date nowDate = DateUtils.getNowDate();
        //数据查询
        //父订单
        Order parentOrder = orderMapper.selectOrderByOrderId(order.getOrderId());
        //查看最新的续租订单
        Order linkedOrder = orderMapper.selectNewOrderByLinkedOrderId(order.getOrderId());

        Order byOrderId = ObjectUtil.isEmpty(linkedOrder) ? parentOrder : linkedOrder;
        House house = houseService.selectHouseById(byOrderId.getHouseId());
        HousingAllocation allocation = housingAllocationService.selectHousingAllocationByHouseId(byOrderId.getHouseId());
        UnsubscribeRule unsubscribeRule = unsubscribeRuleService.selectUnsubscribeRuleById(allocation.getUnsubscribeRuleId());
        List<HousingPrice> housingPriceList = housingPriceService.selectHousingPriceByHouseId(byOrderId.getHouseId());

        //续租订单创建
        Order reletOrder = new Order();
        String orderId = "O" + System.currentTimeMillis() + RandomUtils.nextInt(10000, 100000);
        Date checkOutTime = DateUtils.addDays(byOrderId.getCheckOutTime(), order.getRentDay());
        String linkedOrderId = StrUtil.isBlank(byOrderId.getLinkedOrderId()) ? byOrderId.getOrderId() : byOrderId.getLinkedOrderId();
        //计算金额
        ConfirmationVO compute = this.compute(byOrderId.getCheckOutTime(), checkOutTime, orderId, linkedOrderId, allocation, housingPriceList, true, order.getCreateBy());


        BeanUtil.copyProperties(byOrderId, reletOrder);
        reletOrder.setOrderId(orderId);
        reletOrder.setLinkedOrderId(linkedOrderId);
        reletOrder.setOrderTab(OrderTabEnum.ORDER_TAB_TO_BE_SIGNED.getValue());
        reletOrder.setOrderState(OrderStateEnum.ORDER_STATE_RELET_OBLIGATION.getValue());
        reletOrder.setOrderType(Order.ORDER_TYPE_SHORT_LEASE);
        reletOrder.setCreateTime(nowDate);
        reletOrder.setRentalMode(OrderConstants.RENTAL_MODE_DISPOSABLE);
        reletOrder.setOrderSource(OrderConstants.ORDER_SOURCE_ONLINE_BOOKING);
        reletOrder.setCheckInTime(byOrderId.getCheckOutTime());
        reletOrder.setCheckOutTime(checkOutTime);
        reletOrder.setCreateBy(order.getCreateBy());
        reletOrder.setPayTime(null);
        reletOrder.setDeposit(BigDecimal.ZERO);
        List<OrderChargeItem> orderChargeItemList = compute.getOrderChargeItemList();
        if (CollectionUtil.isNotEmpty(orderChargeItemList)) {
            Optional<OrderChargeItem> housePrice = orderChargeItemList.stream().filter(x -> OrderConstants.CHARGE_TYPE_HOUSE_PRICE.equals(x.getChargeType())).findFirst();
            Optional<OrderChargeItem> cashPledge = orderChargeItemList.stream().filter(x -> OrderConstants.CHARGE_TYPE_CASH_PLEDGE.equals(x.getChargeType())).findFirst();
            housePrice.ifPresent(x -> {
                reletOrder.setTotalRent(x.getItemSum());
                reletOrder.setRentPaidNumber(x.getItemSum());
            });
            cashPledge.ifPresent(x -> {
                reletOrder.setDeposit(x.getItemSum());
                reletOrder.setDepositPaidNumber(x.getItemSum());
            });
            orderChargeItemService.insertBatchOrderChargeItem(orderChargeItemList);
        }
        if (CollectionUtil.isNotEmpty(compute.getOrderHousingExpensesList())) {
            orderHousingExpensesService.insertBatchOrderHousingExpenses(compute.getOrderHousingExpensesList());
        }
        //承租人信息插入
        OrderLessee byOrderIdLessee = orderLesseeService.selectOrderLesseeByOrderId(byOrderId.getOrderId());
        byOrderIdLessee.setLesseeId(null);
        byOrderIdLessee.setOrderId(orderId);
        byOrderIdLessee.setCreateBy(order.getCreateBy());
        byOrderIdLessee.setCreateTime(nowDate);
        byOrderIdLessee.setUpdateBy(null);
        byOrderIdLessee.setUpdateTime(null);
        orderLesseeService.insertOrderLessee(byOrderIdLessee);

        //房屋成员信息插入
        List<HouseMember> houseMemberList = houseMemberService.selectHouseMemberListByOrderId(byOrderId.getOrderId());

        if (!houseMemberList.isEmpty()) {
            houseMemberList.forEach(x -> {
                x.setMemberId(null);
                x.setOrderId(orderId);
                x.setCreateBy(order.getCreateBy());
                x.setCreateTime(nowDate);
                x.setUpdateBy(null);
                x.setUpdateTime(null);
            });
            houseMemberService.insertBatchHouseMember(houseMemberList);
        }
        //快照数据插入
        OrderSnapshoot snapshoot = new OrderSnapshoot();
        snapshoot.setOrderId(orderId);
        snapshoot.setHouseContent(GsonUtil.toJson(house));
        snapshoot.setAllocationContent(GsonUtil.toJson(allocation));
        snapshoot.setCalendarContent(GsonUtil.toJson(compute.getCalendarPriceList()));
        snapshoot.setUnsubscribeContent(GsonUtil.toJson(unsubscribeRule));
        orderSnapshootService.insertOrderSnapshoot(snapshoot);
        int result = orderMapper.insertOrder(reletOrder);
        if (result <= 0) {
            throw new ServiceException("续租失败，请刷新后重来");
        }
        redisCache.setCacheObject(OrderConstants.REDIS_OBLIGATION_ORDER_KEY + reletOrder.getOrderId(), reletOrder, 15, TimeUnit.MINUTES);
        return result;
    }

    @Override
    @Transactional
    public int apartmentCheckingOut(Order order) {
        Order byOrderId = orderMapper.selectOrderByOrderId(order.getOrderId());
        BigDecimal orderTotal = byOrderId.getDeposit().add(byOrderId.getTotalRent());
        //创建退房订单
        String checkOutOrderId = "CO" + System.currentTimeMillis() + RandomUtils.nextInt(10000, 100000);
        CheckOutOrder checkOutOrder = new CheckOutOrder();
        checkOutOrder.setCheckOutSource(OrderConstants.CHECK_OUT_SOURCE_ORDER);
        checkOutOrder.setOrderId(byOrderId.getOrderId());
        checkOutOrder.setHouseId(byOrderId.getHouseId());
        checkOutOrder.setRefundOrderState(OrderConstants.ORDER_STATE_REFUNDED);
        List<Order> orderList = orderMapper.selectOrderByLinkedOrderId(order.getOrderId());
        List<String> orderIds = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(orderList)) {
            BigDecimal refundTotal = orderTotal;
            for (Order linkedOrder : orderList) {
                orderIds.add(linkedOrder.getOrderId());
                //统计退款订单总金额
                refundTotal = refundTotal.add(linkedOrder.getTotalRent());
            }
            checkOutOrder.setSuborderIds(StringUtils.join(orderIds, ","));
            checkOutOrder.setTotalRefundAmount(refundTotal);
        } else {
            checkOutOrder.setTotalRefundAmount(orderTotal);
        }
        checkOutOrder.setCheckOutTime(order.getRealityCheckOutTime());
        checkOutOrder.setCheckOutOrderId(checkOutOrderId);
        checkOutOrder.setCreateBy(order.getCreateBy());
        checkOutOrder.setCreateTime(DateUtils.getNowDate());
        checkOutOrder.setTenantId(byOrderId.getTenantId());
        checkOutOrderService.insertCheckOutOrder(checkOutOrder);


        //插入退房数据
        OrderRefundVO vo = this.refundComputeRefund(order.getOrderId(), order.getRealityCheckOutTime());
        if (CollectionUtil.isEmpty(vo.getOrderRefundItemList())) {
            throw new ServiceException("退费记录异常");
        }
        if (CollectionUtil.isNotEmpty(vo.getOrderRefundDetailsList())) {
            //throw new ServiceException("房费详情记录异常");
            vo.getOrderRefundDetailsList().forEach(x -> x.setCheckOutOrderId(checkOutOrderId));
            orderRefundDetailsService.insertBatchOrderRefundDetails(vo.getOrderRefundDetailsList());
        }

        Date nowDate = DateUtils.getNowDate();
        //插入延迟退房费
        BigDecimal totalPrice = vo.getOrderRefundItemList().get(0).getTotalPrice();
        if (StrUtil.equals(order.getChargeType(), "1")) {
            OrderRefundItem refundItem = new OrderRefundItem();
            refundItem.setOrderId(byOrderId.getOrderId());
            refundItem.setHouseId(byOrderId.getHouseId());
            refundItem.setRefundType(OrderConstants.REFUND_TYPE_CHECK_OUT_DELAY);
            refundItem.setRefundQuantity(BigDecimal.ONE);
            refundItem.setItemSum(order.getTotalPrice());
            refundItem.setTenantId(byOrderId.getTenantId());
            refundItem.setCreateBy(order.getCreateBy());
            refundItem.setCreateTime(nowDate);
            refundItem.setAllocationId(vo.getOrderRefundItemList().get(0).getAllocationId());
            totalPrice = totalPrice.subtract(order.getTotalPrice());
            vo.getOrderRefundItemList().add(refundItem);
            //orderRefundItemService.insertOrderRefundItem(refundItem);
        }
        for (OrderRefundItem refundItem : vo.getOrderRefundItemList()) {
            refundItem.setCheckOutOrderId(checkOutOrderId);
            refundItem.setTotalPrice(totalPrice);
        }
        //插入退费相关信息
        orderRefundItemService.insertBatchOrderRefundItem(vo.getOrderRefundItemList());

        byOrderId.setRefundAmount(checkOutOrder.getTotalRefundAmount());
        byOrderId.setRealityCheckOutTime(order.getRealityCheckOutTime());
        byOrderId.setCheckOutApplicationTime(order.getRealityCheckOutTime());
        IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(byOrderId);
        int result = orderStateServerRole.orderCheckingOut(OrderConstants.RECORD_SOURCE_ENTERPRISE, order.getOperatorId());
        if (result <= 0) {
            throw new ServiceException("退房失败，请刷新后重来");
        }
        //修改承租人租赁状态
        orderIds.add(byOrderId.getOrderId());
        orderLesseeService.rentingTerminationByOrderIds(orderIds);
        //更改租客状态
        houseMemberService.deleteHouseMemberByOrderIds(orderIds);

        // 根据房屋ID和用户类型删除锁密码和锁人脸信息
        houseLockService.removeLockPwdAndLockFace(byOrderId.getHouseId(), LockConstants.USER_TYPE_TENANT);

        //添加房管家人脸信息
        List<HouseLock> houseLockList = houseLockService.selectHouseLockByHouseId(byOrderId.getHouseId());
        if (CollectionUtil.isNotEmpty(houseLockList)) {
            Map<String, List<HouseLock>> lockMap = houseLockList.stream().collect(Collectors.groupingBy(HouseLock::getLockState));
            //锁状态正常则授权房管家人脸信息
            List<HouseLock> normalLockList = lockMap.get(LockConstants.LOCK_STATE_NORMAL);
            if (CollectionUtil.isNotEmpty(normalLockList)) {
                for (HouseLock lock : normalLockList) {
                    //授权的房管家人脸信息
                    List<LockFace> adminLockFaces = lockFaceService.selectLockFaceByLockIdAndUserType(lock.getLockId(), LockConstants.USER_TYPE_MANAGER);
                    if (CollectionUtil.isNotEmpty(adminLockFaces)) {
                        for (LockFace lockFace : adminLockFaces) {
                            houseLockService.authorizationLockFace(lock.getMac(), lockFace);
                        }
                    }
                }
            }

            //锁状态异常则删除锁业务数据,锁改为正常状态
            List<HouseLock> freezeLockList = lockMap.get(LockConstants.LOCK_STATE_FREEZE);
            if (CollectionUtil.isNotEmpty(freezeLockList)) {
                //删除锁业务数据
                houseLockService.removeLockPwdAndLockFace(byOrderId.getOrderId());
                //改锁的状态
                houseLockService.updateHouseLockState(byOrderId.getHouseId(), houseLockList);
            }
        }
        return result;
    }

    @Override
    public Order apartmentCheckingOutInfo(String orderId) {
        Order byOrderId = orderMapper.selectOrderByOrderId(orderId);
        if (!StrUtil.equals(byOrderId.getHouseId(), byOrderId.getBeforeHouseId())) {
            House house = houseService.selectHouseById(byOrderId.getHouseId());
            byOrderId.setHouseNew(house);
        }
        if (ObjectUtil.isNotEmpty(byOrderId)) {
            List<OrderChargeItem> chargeItemList = orderChargeItemService.selectOrderChargeItemByOrderIdOrLinkedOrderId(orderId);
            List<OrderHousingExpenses> housingExpensesList = orderHousingExpensesService.selectHousingExpensesByOrderIdOrLinkedOrderId(orderId, false);
            List<OrderRefundItem> orderRefundItemList = orderRefundItemService.selectOrderRefundItemByOrderIdOrLinkedOrderId(orderId);
            List<OrderRefundDetails> refundDetailsList = orderRefundDetailsService.selectRefundDetailsByOrderIdOrLinkedOrderId(orderId);
            OrderHouseInspection orderHouseInspection = orderHouseInspectionService.selectOrderHouseInspectionByOrderId(orderId);

            byOrderId.setOrderChargeItemList(chargeItemList);
            byOrderId.setOrderHousingExpensesList(housingExpensesList);
            byOrderId.setOrderRefundItemList(orderRefundItemList);
            byOrderId.setOrderRefundDetailsList(refundDetailsList);
            byOrderId.setOrderHouseInspection(orderHouseInspection);

            OrderPriceVO orderPriceVO = packageOrderPriceVO(chargeItemList, housingExpensesList, orderRefundItemList, refundDetailsList, orderHouseInspection);
            byOrderId.setOrderPriceVO(orderPriceVO);


            List<Order> orderList = orderMapper.selectOrderByLinkedOrderId(orderId);
            BigDecimal reletPrice = BigDecimal.ZERO;
            if (CollectionUtil.isNotEmpty(orderList)) {
                reletPrice = orderList.stream().map(x -> x.getDeposit().add(x.getTotalRent())).reduce(BigDecimal.ZERO, BigDecimal::add);
                byOrderId.setCheckOutTime(orderList.get(orderList.size() - 1).getCheckOutTime());
            }
            byOrderId.setReletPrice(reletPrice);

            CheckOutOrder checkOutOrder = checkOutOrderService.selectCheckOutOrderByOrderId(orderId);
            byOrderId.setCheckOutOrder(checkOutOrder);
        }
        return byOrderId;
    }

    @Override
    public OrderPriceVO packageOrderPriceVO(List<OrderChargeItem> chargeItemList, List<OrderHousingExpenses> housingExpensesList,
                                            List<OrderRefundItem> orderRefundItemList, List<OrderRefundDetails> refundDetailsList,
                                            OrderHouseInspection orderHouseInspection) {
        OrderPriceVO orderPriceVO = new OrderPriceVO();
//        List<OrderChargeItem> chargeItemList = orderChargeItemService.selectOrderChargeItemByOrderIdOrLinkedOrderId(orderId);
//        List<OrderHousingExpenses> housingExpensesList = orderHousingExpensesService.selectHousingExpensesByOrderIdOrLinkedOrderId(orderId, false);
//        List<OrderRefundItem> orderRefundItemList = orderRefundItemService.selectOrderRefundItemByOrderIdOrLinkedOrderId(orderId);
//        List<OrderRefundDetails> refundDetailsList = orderRefundDetailsService.selectRefundDetailsByOrderIdOrLinkedOrderId(orderId);


        //按照收费类型分组
        Map<String, List<OrderChargeItem>> chargeItemListMap = chargeItemList.stream().collect(Collectors.groupingBy(OrderChargeItem::getChargeType));
        //按照退款类型分组
        Map<String, List<OrderRefundItem>> refundItemListMap = orderRefundItemList.stream().collect(Collectors.groupingBy(OrderRefundItem::getRefundType));
        //按照退费类型分组
        Map<String, List<OrderRefundDetails>> refundDetailsListMap = refundDetailsList.stream().collect(Collectors.groupingBy(OrderRefundDetails::getRefundType));

        //获取房费收费项
        List<OrderChargeItem> housePriceItemList = chargeItemListMap.get(OrderConstants.CHARGE_TYPE_HOUSE_PRICE);
        BigDecimal houseItemSum = housePriceItemList.stream().map(OrderChargeItem::getItemSum).reduce(BigDecimal.ZERO, BigDecimal::add);
        OrderChargeItem orderChargeItem = new OrderChargeItem();
        orderChargeItem.setChargeType(OrderConstants.CHARGE_TYPE_HOUSE_PRICE);
        orderChargeItem.setItemSum(houseItemSum);
        orderChargeItem.setOrderChargeItemList(housePriceItemList);
        orderPriceVO.setHouseChargeItem(orderChargeItem);

        //获取押金收费项
        Optional<OrderChargeItem> first = chargeItemListMap.get(OrderConstants.CHARGE_TYPE_CASH_PLEDGE).stream().filter(x -> StrUtil.isBlank(x.getLinkedOrderId())).findFirst();
        first.ifPresent(orderPriceVO::setCashPledgeChargeItem);

        //封装已住房费项
        List<OrderRefundDetails> checkInDetailsList = refundDetailsListMap.get(OrderConstants.REFUND_TYPE_CHECKED_IN);
        if (CollectionUtil.isNotEmpty(checkInDetailsList)) {
            OrderRefundDetails checkInDetails = new OrderRefundDetails();
            checkInDetails.setRefundType(OrderConstants.REFUND_TYPE_CHECKED_IN);
            BigDecimal houseRefundPrice = checkInDetailsList.stream().map(OrderRefundDetails::getRefundPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            checkInDetails.setOrderRefundDetailsList(checkInDetailsList);
            checkInDetails.setRefundPrice(houseRefundPrice);
            orderPriceVO.setHouseRefundItem(checkInDetails);
        }

        //封装退订房费项
        List<OrderRefundDetails> unsubscribeDetailsList = refundDetailsListMap.get(OrderConstants.REFUND_TYPE_UNSUBSCRIBE);
        if (CollectionUtil.isNotEmpty(unsubscribeDetailsList)) {
            OrderRefundDetails unsubscribeDetails = new OrderRefundDetails();
            unsubscribeDetails.setRefundType(OrderConstants.REFUND_TYPE_UNSUBSCRIBE);
            BigDecimal unsubscribeRefundPrice = unsubscribeDetailsList.stream().map(OrderRefundDetails::getRefundPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            unsubscribeDetails.setOrderRefundDetailsList(unsubscribeDetailsList);
            unsubscribeDetails.setRefundPrice(unsubscribeRefundPrice);
            orderPriceVO.setUnsubscribeRefundItem(unsubscribeDetails);
        }

        List<OrderRefundItem> facilityRefundItem = refundItemListMap.get(OrderConstants.REFUND_TYPE_FACILITY);
        if (CollectionUtil.isNotEmpty(facilityRefundItem)) {
            OrderRefundItem orderRefundItem = new OrderRefundItem();
            orderRefundItem.setRefundType(OrderConstants.REFUND_TYPE_FACILITY);
            orderRefundItem.setItemSum(facilityRefundItem.stream().map(OrderRefundItem::getItemSum).reduce(BigDecimal.ZERO, BigDecimal::add));
            //OrderHouseInspection orderHouseInspection = orderHouseInspectionService.selectOrderHouseInspectionByOrderId(orderId);
            if (ObjectUtil.isNotEmpty(orderHouseInspection)) {
                orderRefundItem.setFacilityDetailList(orderHouseInspection.getFacilityDetailList());
            }
            orderPriceVO.setFacilityRefundItem(orderRefundItem);
        }

        List<OrderRefundItem> checkOutDelayRefundItem = refundItemListMap.get(OrderConstants.REFUND_TYPE_CHECK_OUT_DELAY);
        if (CollectionUtil.isNotEmpty(checkOutDelayRefundItem)) {
            OrderRefundItem orderRefundItem = new OrderRefundItem();
            orderRefundItem.setRefundType(OrderConstants.REFUND_TYPE_CHECK_OUT_DELAY);
            orderRefundItem.setItemSum(checkOutDelayRefundItem.stream().map(OrderRefundItem::getItemSum).reduce(BigDecimal.ZERO, BigDecimal::add));
            orderPriceVO.setCheckOutDelayRefundItem(orderRefundItem);
        }

        BigDecimal totalHouse = housingExpensesList.stream().map(OrderHousingExpenses::getRentingExpenses).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal refundHouse = refundDetailsList.stream().map(OrderRefundDetails::getRefundPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal serviceCharge = totalHouse.subtract(refundHouse);
        if (BigDecimal.ZERO.compareTo(serviceCharge) < 0) {
            OrderRefundItem serviceChargeItem = new OrderRefundItem();
            serviceChargeItem.setItemSum(serviceCharge);
            orderPriceVO.setServiceCharge(serviceChargeItem);
        }
        return orderPriceVO;
    }

    /**
     * 短租订单退房订单--已完成（退费处理）
     */
    @Override
    @Transactional
    public AjaxResult apartmentCompleted(Order order) {
        Order orderByOrderId = orderMapper.selectOrderByOrderId(order.getOrderId());
        if (StrUtil.equals(OrderConstants.SHOW_STATE_NO, orderByOrderId.getShowState())) {
            throw new ServiceException("订单已被删除");
        }
        if (!OrderStateEnum.ORDER_STATE_CHECKING_OUT.getValue().equals(orderByOrderId.getOrderState())) {
            throw new ServiceException("订单状态异常，请刷新重来");
        }

        Date nowDate = DateUtils.getNowDate();

        CheckOutOrder checkOutOrder = checkOutOrderService.selectCheckOutOrderByOrderId(order.getOrderId());

        //房费每日详情修改，及统计退款的金额总金额
        List<OrderRefundDetails> refundDetailsList = orderRefundDetailsService.selectRefundDetailsByOrderIdOrLinkedOrderId(order.getOrderId());
        //房费不需要的退款金额
        BigDecimal housePrice = BigDecimal.ZERO;
        //不需要退的房费详情id集合
        List<Long> refundDetailsIds = order.getRefundDetailsIds();
        if (CollectionUtil.isNotEmpty(refundDetailsIds)) {
            for (OrderRefundDetails refundDetails : refundDetailsList) {
                //退款每日详情包含指定退款的，则修改状态为退款成功
                if (OrderConstants.REFUND_TYPE_UNSUBSCRIBE.equals(refundDetails.getRefundType())) {
                    if (refundDetailsIds.contains(refundDetails.getId())) {
                        housePrice = housePrice.add(refundDetails.getRefundPrice());
                        refundDetails.setRefundState(OrderConstants.REFUND_STATE_NO);
                    } else {
                        refundDetails.setRefundState(OrderConstants.REFUND_STATE_YES);
                    }
                } else if (OrderConstants.REFUND_TYPE_CHECKED_IN.equals(refundDetails.getRefundType())) {
                    housePrice = housePrice.add(refundDetails.getRefundPrice());
                }

            }
        } else {
            for (OrderRefundDetails refundDetails : refundDetailsList) {
                if (OrderConstants.REFUND_TYPE_UNSUBSCRIBE.equals(refundDetails.getRefundType())) {
                    refundDetails.setRefundState(OrderConstants.REFUND_STATE_YES);
                } else if (OrderConstants.REFUND_TYPE_CHECKED_IN.equals(refundDetails.getRefundType())) {
                    housePrice = housePrice.add(refundDetails.getRefundPrice());
                }
            }
        }
        BigDecimal refundPrice = BigDecimal.ZERO;
        orderRefundDetailsService.updateBatchOrderRefundDetails(refundDetailsList);
        List<OrderRefundItem> refundItemList = orderRefundItemService.selectOrderRefundItemByOrderIdOrLinkedOrderId(order.getOrderId());
        /*for (OrderRefundItem refundItem : refundItemList) {
            if (StrUtil.equals(OrderConstants.REFUND_TYPE_HOUSE_PRICE, refundItem.getRefundType())) {
                refundItem.setItemSum(housePrice);
            }
//            totalPrice = totalPrice.add(refundItem.getItemSum());
        }*/

        /*List<OrderRefundItem> cashPledgeItemList = refundItemList.stream().filter(x -> OrderConstants.REFUND_TYPE_CASH_PLEDGE.equals(x.getRefundType()))
                .collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(cashPledgeItemList)) {
            cashPledgePrice = cashPledgeItemList.get(0).getItemSum();
        }*/
        //损坏赔偿
        List<OrderRefundItem> facilityItemList = refundItemList.stream().filter(x -> OrderConstants.REFUND_TYPE_FACILITY.equals(x.getRefundType()))
                .collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(facilityItemList)) {
            refundPrice = refundPrice.add(facilityItemList.get(0).getItemSum());
        }
        //延迟退房费
        List<OrderRefundItem> checkOutDelayItemList = refundItemList.stream().filter(x -> OrderConstants.REFUND_TYPE_CHECK_OUT_DELAY.equals(x.getRefundType()))
                .collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(checkOutDelayItemList)) {
            refundPrice = refundPrice.add(checkOutDelayItemList.get(0).getItemSum());
        }
        BigDecimal totalPrice = refundPrice.add(housePrice);
        for (OrderRefundItem refundItem : refundItemList) {
            refundItem.setTotalPrice(totalPrice);
        }
        orderRefundItemService.updateBatchOrderRefundItem(refundItemList);

        BigDecimal houseTotalPrice = refundDetailsList.stream().map(OrderRefundDetails::getRefundPrice).reduce(BigDecimal.ZERO, BigDecimal::add);

        BigDecimal totalRefundAmount = orderByOrderId.getDeposit().add(houseTotalPrice);

        if (totalRefundAmount.compareTo(totalPrice) > 0) {
            //大于0则退款
            //需要退款的金额
            BigDecimal subtract = totalRefundAmount.subtract(totalPrice);
            orderByOrderId.setRefundAmount(subtract);
            checkOutOrder.setTotalRefundAmount(subtract);

            WechatAccount account = wechatAccountService.selectWechatAccountByTenantId(orderByOrderId.getTenantId());
            if (ObjectUtil.isEmpty(account)) {
                throw new ServiceException("商户号数据异常");
            }
            OSSObject object = ossService.getObject(account.getAccountCertificate());
            byte[] bytes = ossService.parseObject(object);
            if (bytes == null) {
                throw new ServiceException("商户证书获取异常");
            }
            List<Order> orderList = new ArrayList<>();
            orderList.add(orderByOrderId);
            List<Order> linkedOrderList = orderMapper.selectOrderByLinkedOrderId(order.getOrderId());
            if (CollectionUtil.isNotEmpty(linkedOrderList)) {
                orderList.addAll(linkedOrderList);
            }
            orderList = orderList.stream()
                    .sorted(Comparator.comparing(Order::getCheckInTime))
                    .collect(Collectors.toList());
            List<CheckOutSubOrder> checkOutSubOrderList = new ArrayList<>();
            String refundOrderState = OrderConstants.ORDER_STATE_REFUND_SUCCESSFUL;
            for (Order currentOrder : orderList) {
                //如果需要退款的金额小于等于0，则跳出循环退款的逻辑
                if (subtract.compareTo(BigDecimal.ZERO) <= 0) {
                    break;
                }
                RefundOrder refundOrder = new RefundOrder();
                refundOrder.setAppId(weChatConfig.getAppId());
                refundOrder.setMchId(account.getAccountId());
                refundOrder.setMchApiKey(account.getAccountApiKey());

                refundOrder.setOutTradeNo(currentOrder.getOrderId());
                refundOrder.setOutRefundNo(currentOrder.getOrderId());
                BigDecimal add = currentOrder.getDeposit().add(currentOrder.getTotalRent());
                BigDecimal currentRefund = BigDecimal.ZERO;
                if (add.compareTo(subtract) > 0) {
//                        currentRefund = add.subtract(subtract);
                    currentRefund = subtract;
                    subtract = BigDecimal.ZERO;
                } else if (add.compareTo(subtract) == 0) {
                    currentRefund = add;
                    subtract = BigDecimal.ZERO;
                } else if (add.compareTo(subtract) < 0) {
                    subtract = subtract.subtract(add);
                    currentRefund = add;
                }
                int refund = currentRefund.multiply(BigDecimal.valueOf(100)).intValue();
                refundOrder.setTotalFee(1/*refund*/);
                refundOrder.setRefundFee(1/*refund*/);
                refundOrder.setNotifyUrl(weChatConfig.getCheckOutCallBackUrl());
                refundOrder.setMchCertificate(bytes);
                AjaxResult ajaxResult = weChatService.refundOrder(refundOrder);
                CheckOutSubOrder checkOutSubOrder = new CheckOutSubOrder();
                checkOutSubOrder.setCheckOutOrderId(checkOutOrder.getCheckOutOrderId());
                checkOutSubOrder.setOrderId(currentOrder.getOrderId());
                checkOutSubOrder.setLinkedOrderId(currentOrder.getLinkedOrderId());
                checkOutSubOrder.setHouseId(currentOrder.getHouseId());
                checkOutSubOrder.setCreateBy(order.getCreateBy());
                checkOutSubOrder.setCreateTime(nowDate);
                if (HttpStatus.SUCCESS == (int) ajaxResult.get("code")) {
                    checkOutSubOrder.setRefundOrderState(OrderConstants.ORDER_STATE_REFUND_SUCCESSFUL);
                } else {
                    checkOutSubOrder.setRefundOrderState(OrderConstants.ORDER_STATE_REFUND_EXCEPTION);
                    refundOrderState = OrderConstants.ORDER_STATE_REFUND_EXCEPTION;
                }
                checkOutSubOrder.setRefundAmount(currentRefund);

                checkOutSubOrderList.add(checkOutSubOrder);
                if (!StrUtil.equals(orderByOrderId.getOrderId(), currentOrder.getOrderId())) {
                    //填写退款金额
                    currentOrder.setRefundAmount(currentRefund);
                    IOrderStateServerRole linkedOrderRole = new OrderStateServerRole(currentOrder);
                    linkedOrderRole.orderCompletion(OrderConstants.RECORD_SOURCE_ENTERPRISE, order.getOperatorId());
                }
            }
            if (CollectionUtil.isNotEmpty(checkOutSubOrderList)) {
                checkOutSubOrderService.insertBatchCheckOutSubOrder(checkOutSubOrderList);
            }
            checkOutOrder.setRefundOrderState(refundOrderState);
            checkOutOrderService.updateCheckOutOrder(checkOutOrder);
            orderMapper.updateBatchOrder(orderList);
        } else if (totalRefundAmount.compareTo(totalPrice) < 0) {
            BigDecimal payPrice = totalPrice.subtract(totalRefundAmount);
            //小于0则支付
            checkOutOrder.setTotalRefundAmount(payPrice);
            checkOutOrder.setRefundOrderState(OrderConstants.ORDER_STATE_OBLIGATION);
            orderMapper.updateOrderRefundAmount(orderByOrderId.getOrderId());
            orderByOrderId.setSupplementaryPayment(payPrice);
            orderByOrderId.setRefundAmount(null);
            checkOutOrderService.updateCheckOutOrder(checkOutOrder);
        } else if (totalRefundAmount.compareTo(totalPrice) == 0) {
            checkOutOrder.setRefundOrderState(OrderConstants.ORDER_STATE_REFUND_SUCCESSFUL);
            checkOutOrder.setTotalRefundAmount(BigDecimal.ZERO);
            checkOutOrderService.updateCheckOutOrder(checkOutOrder);
        }
        // 修改订单状态
        IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(orderByOrderId);
        orderStateServerRole.orderCompletion(OrderConstants.RECORD_SOURCE_ENTERPRISE, order.getOperatorId());
        return AjaxResult.success();
    }

    @Override
    public void paymentTimeout(String orderId) {
        Order order = orderMapper.selectOrderByOrderId(orderId);
        if (ObjectUtil.isNull(order)) {
            log.error("订单不存在:{}", orderId);
            return;
        }
        String orderState = order.getOrderState();
        if (!(StrUtil.equals(orderState, OrderStateEnum.ORDER_STATE_OBLIGATION.getValue()) ||
                StrUtil.equals(orderState, OrderStateEnum.ORDER_STATE_RELET_OBLIGATION.getValue()))) {
            log.error("订单状态异常");
            return;
        }

        //订单超时，自动取消订单
        IOrderStateServerRole orderStateRecord = new OrderStateServerRole(order);
        orderStateRecord.orderCancellation(OrderConstants.RECORD_SOURCE_ENTERPRISE, "订单超时，自动取消订单");
    }

    @Override
    public void checkOutCallbackOrder(RefundParam refundParam, RefundReqInfo reqInfo) {
        String outTradeNo = reqInfo.getOutTradeNo();
        Order order = orderMapper.selectOrderByOrderId(outTradeNo);
        CheckOutSubOrder checkOutSubOrder = checkOutSubOrderService.selectCheckOutSubOrderByOrderId(outTradeNo);
        if (ObjectUtil.isEmpty(order) || ObjectUtil.isEmpty(checkOutSubOrder)) {
            log.info("当前退款回调的单号查询不到订单数据:{},{}", GsonUtil.toJson(refundParam), GsonUtil.toJson(reqInfo));
            return;
        }
        if (StrUtil.isNotBlank(refundParam.getReturnCode()) && StrUtil.equals(refundParam.getReturnCode(), "SUCCESS")) {
            IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(order);
            orderStateServerRole.orderCompletion(OrderConstants.RECORD_SOURCE_ENTERPRISE, null);
            checkOutSubOrder.setRefundOrderState(OrderConstants.ORDER_STATE_REFUND_SUCCESSFUL);
        } else {
            checkOutSubOrder.setRefundOrderState(OrderConstants.ORDER_STATE_REFUND_EXCEPTION);
        }
        checkOutSubOrderService.updateCheckOutSubOrder(checkOutSubOrder);
        if (!checkOutSubOrderService.checkOrderState(checkOutSubOrder.getCheckOutOrderId())) {
            CheckOutOrder checkOutOrder = new CheckOutOrder();
            checkOutOrder.setCheckOutOrderId(checkOutSubOrder.getCheckOutOrderId());
            checkOutOrder.setRefundOrderState(OrderConstants.ORDER_STATE_REFUND_SUCCESSFUL);
            checkOutOrder.setUpdateTime(DateUtils.getNowDate());
            checkOutOrderService.updateCheckOutOrder(checkOutOrder);
        }
    }

    @Override
    public Map<String, Object> countOrderState(Long userId) {
        Map<String, Object> map = new HashMap<>();
        int obligation = orderMapper.countOrderState(userId, OrderStateEnum.ORDER_STATE_OBLIGATION.getValue());
        map.put(OrderStateEnum.ORDER_STATE_OBLIGATION.getValue(), obligation);
        int stayCheckIn = orderMapper.countOrderState(userId, OrderStateEnum.ORDER_STATE_STAY_CHECK_IN.getValue());
        map.put(OrderStateEnum.ORDER_STATE_STAY_CHECK_IN.getValue(), stayCheckIn);
        int checkIn = orderMapper.countOrderState(userId, OrderStateEnum.ORDER_STATE_CHECK_IN.getValue());
        map.put(OrderStateEnum.ORDER_STATE_CHECK_IN.getValue(), checkIn);
        int checkingOut = orderMapper.countOrderState(userId, OrderStateEnum.ORDER_STATE_CHECKING_OUT.getValue());
        map.put(OrderStateEnum.ORDER_STATE_CHECKING_OUT.getValue(), checkingOut);

        int result = checkOutOrderService.countOrderState(userId);
        int result1 = orderAuditRecordService.apartmentCountOrderState(userId);
        map.put(OrderStateEnum.ORDER_STATE_UNSUBSCRIBING.getValue() + "-"
                + OrderStateEnum.ORDER_STATE_CHECKING_OUT.getValue(), result + result1);

        return map;
    }

    @Override
    public List<Order> selectOrderByLinkedOrderId(String orderId) {
        return orderMapper.selectOrderByLinkedOrderId(orderId);
    }

    @Override
    public Order selectNewOrderByLinkedOrderId(String orderId) {
        return orderMapper.selectNewOrderByLinkedOrderId(orderId);
    }

    @Override
    public String checkLinkedOrder(String orderId) {
        int result = orderMapper.checkLinkedOrder(orderId);
        return result > 0 ? "1" : "0";
    }

    @Override
    public List<Order> selectOrderByHouseIds(String[] houseIds) {
        return orderMapper.selectOrderByHouseIds(houseIds);

    }

    @Override
    public List<Order> selectOrderByHouseIdAndCheckIn(String houseId) {
        return orderMapper.selectOrderByHouseIdAndCheckIn(houseId);
    }

    public void reviewCancelReservationOrderTimeOut(Long recordId) {
        OrderAuditRecord auditRecord = orderAuditRecordService.selectOrderAuditRecordByRecordId(recordId);
        //房费每日详情修改，及统计退款的金额总金额
        List<OrderRefundDetails> refundDetailsList = orderRefundDetailsService.selectOrderRefundDetailsByOrderId(auditRecord.getOrderId());
        auditRecord.setAuditRecordState(OrderConstants.AUDIT_RECORD_STATE_PASS);
        auditRecord.setAuditProcess(OrderConstants.AUDIT_PROCESS_REFUND);
        auditRecord.setRemark("订单超时，自动审核通过");
        Date nowDate = DateUtils.getNowDate();
        auditRecord.setUpdateTime(nowDate);
        auditRecord.setAuditTime(nowDate);
        int result = orderAuditRecordService.updateOrderAuditRecord(auditRecord);
        if (result > 0) {
            //删除redis的key，防止触发缓存过期回调时间
            redisCache.deleteObject(OrderConstants.REDIS_AUDIT_ORDER_KEY + recordId);
        }
        //填写退款金额
        Order order = this.selectOrderById(auditRecord.getOrderId());
        BigDecimal totalPrice = BigDecimal.ZERO;
        BigDecimal housePrice = BigDecimal.ZERO;
        //需要退的房费详情id集合
        for (OrderRefundDetails refundDetails : refundDetailsList) {
            refundDetails.setRefundState(OrderConstants.REFUND_STATE_YES);
            housePrice = housePrice.add(refundDetails.getRefundPrice());
        }
        orderRefundDetailsService.updateBatchOrderRefundDetails(refundDetailsList);
        List<OrderRefundItem> refundItemList = orderRefundItemService.selectOrderRefundItemByOrderIdAndRecordId(auditRecord.getOrderId(), auditRecord.getRecordId());
        for (OrderRefundItem refundItem : refundItemList) {
            if (StrUtil.equals(OrderConstants.REFUND_TYPE_HOUSE_PRICE, refundItem.getRefundType())) {
                refundItem.setItemSum(housePrice);
            } else if (StrUtil.equals(OrderConstants.REFUND_TYPE_CASH_PLEDGE, refundItem.getRefundType())) {
                totalPrice = housePrice.add(refundItem.getItemSum());
            }
        }
        BigDecimal finalTotalPrice = totalPrice;
        refundItemList.forEach(x -> x.setTotalPrice(finalTotalPrice));
        orderRefundItemService.updateBatchOrderRefundItem(refundItemList);

        order.setRefundAmount(totalPrice);
        orderMapper.updateOrder(order);
        if (result > 0) {
            WechatAccount account = wechatAccountService.selectWechatAccountByTenantId(auditRecord.getTenantId());
            if (ObjectUtil.isEmpty(account)) {
                throw new ServiceException("商户号数据异常");
            }
            RefundOrder refundOrder = new RefundOrder();
            refundOrder.setAppId(weChatConfig.getAppId());
            refundOrder.setMchId(account.getAccountId());
            refundOrder.setMchApiKey(account.getAccountApiKey());
            OSSObject object = ossService.getObject(account.getAccountCertificate());
            byte[] bytes = ossService.parseObject(object);
            if (bytes == null) {
                throw new ServiceException("商户证书获取异常");
            }
            refundOrder.setMchCertificate(bytes);

            refundOrder.setOutTradeNo(auditRecord.getOrderId());
            refundOrder.setOutRefundNo(auditRecord.getOrderId());
            //int refund = totalPrice.multiply(BigDecimal.valueOf(100)).intValue();
            refundOrder.setTotalFee(1/*refund*/);
            refundOrder.setRefundFee(1/*refund*/);
            refundOrder.setNotifyUrl(weChatConfig.getCancelReservationCallBackUrl());
            weChatService.refundOrder(refundOrder);
        }
    }

    @Override
    public List<Order> selectAddBillList(Order order) {
        return orderMapper.selectAddBillList(order);
    }

    @Override
    public List<OrderVO> selectRentTimeList(String houseId) {
        return orderMapper.selectRentTimeList(houseId);
    }

    @Override
    @Transactional
    public AjaxResult cancel(String orderId) {
        Order order = orderMapper.selectOrderByOrderId(orderId);
        if ( !StrUtil.equals(OrderStateEnum.ORDER_STATE_TO_BE_SIGNED.getValue(), order.getOrderState())) {
            return AjaxResult.error("订单状态异常，不能作废订单");
        }

        // 更改订单状态
        IOrderStateServerRole orderStateServerRole = new OrderStateServerRole(order);
        orderStateServerRole.cancel();

        // 撤销合同
        lesseeContractService.repealLesseeContractByOrderId(orderId);
        return AjaxResult.success();
    }

    @Override
    public List<Order> selectEffectiveOrderByHouseId(String houseId) {
        return orderMapper.selectEffectiveOrderByHouseId(houseId);
    }

    @Override
    public void authorizedFace(Order order) {
        List<HouseLock> houseLockList = houseLockService.selectHouseLockByHouseIdAndLockState(order.getHouseId(), HouseLock.LOCK_STATE_FROZEN);

        if (CollectionUtil.isEmpty(houseLockList) || !order.getCheckOutTime().after(DateUtils.getNowDate())) {
            return;
        }

        houseLockList.forEach(houseLock -> {
            List<LockFace> lockFaceList = lockFaceService.selectLockFaceListAndLockId(houseLock.getLockId());
            if (CollectionUtil.isNotEmpty(lockFaceList)) {
                lockFaceList.forEach(lockFace -> {
                    if (LockConstants.USER_TYPE_MANAGER.equals(lockFace.getUserType()) && LockConstants.FACE_STATE_ENABLED.equals(lockFace.getFaceState())) {
                        houseLockService.disableLockFaceAndFaceState(houseLock, lockFace);
                    } else {
                        lockDevicesService.createLockFace(lockFace.getImg(), houseLock.getMac(), lockFace.getIdentification());
                    }
                });
            }
        });

        houseLockService.updateHouseLockState(order.getHouseId(), houseLockList);
    }

    @Override
    public boolean checkReturnOrderByOrderId(String orderId) {
        return orderMapper.checkReturnOrderByOrderId(orderId) > 0;
    }

    public void packageOrderRefundItem(List<OrderChargeItem> chargeItemList, Order order, Date date, List<OrderRefundItem> orderRefundItemList, BigDecimal totalRent) {
        for (OrderChargeItem chargeItem : chargeItemList) {
            OrderRefundItem refundItem = new OrderRefundItem();
            String refundType = null;
            if (StrUtil.equals(OrderConstants.CHARGE_TYPE_HOUSE_PRICE, chargeItem.getChargeType())) {
                refundType = OrderConstants.REFUND_TYPE_HOUSE_PRICE;
                refundItem.setItemSum(chargeItem.getItemSum().subtract(totalRent));
            } else if (StrUtil.equals(OrderConstants.CHARGE_TYPE_CASH_PLEDGE, chargeItem.getChargeType())) {
                refundType = OrderConstants.REFUND_TYPE_CASH_PLEDGE;
                refundItem.setItemSum(chargeItem.getItemSum());
            }
            refundItem.setRefundType(refundType);
            refundItem.setOrderId(chargeItem.getOrderId());
            refundItem.setLinkedOrderId(chargeItem.getLinkedOrderId());
            refundItem.setHouseId(chargeItem.getHouseId());
            refundItem.setAllocationId(chargeItem.getAllocationId());
            refundItem.setRefundQuantity(chargeItem.getPurchaseQuantity());
            refundItem.setTotalPrice(chargeItem.getTotalPrice().subtract(totalRent));
            refundItem.setTenantId(order.getTenantId());
            refundItem.setCreateTime(date);
            refundItem.setCreateBy(order.getCreateBy());
            orderRefundItemList.add(refundItem);
        }
    }

    public void packageHousingExpenses(OrderHousingExpenses expenses, List<OrderRefundDetails> refundDetailsList, Date date, String refundState, String refundType) {
        OrderRefundDetails refundDetails = new OrderRefundDetails();
        refundDetails.setAllocationId(expenses.getAllocationId());
        refundDetails.setOrderId(expenses.getOrderId());
        refundDetails.setLinkedOrderId(expenses.getLinkedOrderId());
        refundDetails.setHouseId(expenses.getHouseId());
        refundDetails.setRefundTime(expenses.getRentingTime());
        refundDetails.setRefundPrice(expenses.getRentingExpenses());
        refundDetails.setTenantId(expenses.getTenantId());
        refundDetails.setRefundState(refundState);
        refundDetails.setRefundType(refundType);
        refundDetails.setCreateTime(date);
        refundDetails.setCreateBy(expenses.getCreateBy());
        refundDetailsList.add(refundDetails);
    }
}
